【Spring源码】小白速通解析Spring源码,从0到1,持续更新!

这篇具有很好参考价值的文章主要介绍了【Spring源码】小白速通解析Spring源码,从0到1,持续更新!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Spring源码

参考资料

https://www.bilibili.com/video/BV1Tz4y1a7FM

https://www.bilibili.com/video/BV1iz4y1b75q

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

bean工厂

DefaultListableBeanFactory(最原始)

bean的生命周期

创建(实例化)–>依赖注入–>-初始化–>销毁

bean–>推断构造方法(默认是无参构造,或指定的构造方法)–>实例化成普通对象(相当于new bean)

–>进行依赖注入(bean里的属性)–>执行afterPropertiesSet()(InitializingBean的一个回调方法,同@PostConstruct)

–>初始化后是否需要AOP–>AOP–>代理对象(target=普通对象)–>把对象放入Map<beanname,bean对象>单例池

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

//真正创建Bean的方法
	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		//封装被创建的Bean对象
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		//获取实例化对象的类型
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		//调用PostProcessor后置处理器
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		//向容器中缓存单例模式的Bean对象,以防循环引用
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		//Bean对象的初始化,依赖注入在此触发
		//这个exposedObject在初始化完成之后返回作为依赖注入完成后的Bean
		Object exposedObject = bean;
		try {
			//将Bean实例对象封装,并且Bean定义中配置的属性值赋值给实例对象
			populateBean(beanName, mbd, instanceWrapper);
			//初始化Bean对象
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			//获取指定名称的已注册的单例模式Bean对象
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				//根据名称获取的已注册的Bean和正在实例化的Bean是同一个
				if (exposedObject == bean) {
					//当前实例化的Bean初始化完成
					exposedObject = earlySingletonReference;
				}
				//当前Bean依赖其他Bean,并且当发生循环引用时不允许新创建实例对象
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					//获取当前Bean所依赖的其他Bean
					for (String dependentBean : dependentBeans) {
						//对依赖Bean进行类型检查
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		//注册完成依赖注入的Bean
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}
//初始容器创建的Bean实例对象,为其添加BeanPostProcessor后置处理器
	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		//JDK的安全机制验证权限
		if (System.getSecurityManager() != null) {
			//实现PrivilegedAction接口的匿名内部类
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			//为Bean实例对象包装相关属性,如名称,类加载器,所属容器等信息
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		//对BeanPostProcessor后置处理器的postProcessBeforeInitialization
		//回调方法的调用,为Bean实例初始化前做一些处理
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		//调用Bean实例对象初始化的方法,这个初始化方法是在Spring Bean定义配置
		//文件中通过init-method属性指定的
		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		//对BeanPostProcessor后置处理器的postProcessAfterInitialization
		//回调方法的调用,为Bean实例初始化之后做一些处理
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

三级缓存解决循环依赖

循环依赖

在A创建的过程中,A的属性B需要注入属性A

  • singletonObjects(一级缓存)
  • earlysingletonObjects(二级缓存)
  • singletonFactories(三级缓存)
  • private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
  1. 创建的A放入 Set singletonsCurrentlyInCreation(只要创建就放入set,表示bean正在初始化)
  2. 首先是实例化,new 普通对象,addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));为了防止循环引用,尽早持有对象的引用,第二个参数是一个lamda表达式可用来获取普通对象
  3. 在A填充B时,B需要注入A,判断A正在初始化,此时出现循环依赖
  4. 先向二级缓存里查找,在多方循环中保证创建的是都是同一个代理对象A
  5. 再向三级缓存里查找,没有则执行lamda获取普通对象,并且进行AOP,生成代理对象
  6. 放入bean到二级缓存中
  7. 填充其他的属性
  8. 进行Aop的逻辑,若是循环依赖则会提前进行Aop(step5)而不是现在
  9. 在二级缓存里查找,是不是已经有已经生成好的bean
  10. 添加到单例池
  11. Set中removeA,标识初始化完成

beanFactory

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

四个Applicationcontext

FileSystemXmlApplicationContext

ClassPathXmlApplicationContext

AnnotationConfigApplicationContext

AnnotationConfigWebApplicationContext

GenericApplicationContext(是一个干净的容器)

后置处理器(PostProcessor)

CommonAnnotationBeanPostProcessor

Ordered.LOWEST_PRECEDENCE - 3

@Resource @PostConstruct @PreDestroy

解析WebService关于JAX-WS的相关注解,EJB相关的注解

AutowiredAnnotationBeanPostProcessor

Ordered.LOWEST_PRECEDENCE - 2

处理@Autowire注解,@Value注解,处理javax.inject.Inject JSR-330注解

	//处理类中的属性
	@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

		//获取指定类中autowire相关注解的元信息
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			//对Bean的属性进行自动注入
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

BeanPostProcessor

处理器定义了Bean 初始化 前后执行的方法。

public interface BeanPostProcessor {

    //自定义初始化方法之前执行
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    //自定义初始化方法之后执行
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}

InstantiationAwareBeanPostProcessor

该处理器定义了Bean 实例化 前后执行的方法。

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    //实例化之前
    @Nullable
    default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { 
        //这里可以自定义代理类
        return null;
    }

    //实例化后-但是执行在初始化之前
    default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

    //处理bean的Properties值
    @Nullable
    default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
            throws BeansException {

        return null;
    }

}

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

DestructionAwareBeanPostProcessor

该处理器了销毁Bean之前的操作。

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {

    //bean销毁之前
    void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;

    //bean是否需要销毁
    default boolean requiresDestruction(Object bean) {
        return true;
    }

}

工厂后置处理器-扫描

AnnotationBeanNameGenerator(bean名构造器)

MetadataReader(类信息)

AnnotationMetadata(注解信息)

ClassPathBeanDefinitionScanner(mapperscaner)

一、自定义Bean 后处理器 Processor

package com.mangoubiubiu.show.a05.component;

import com.mangoubiubiu.show.a05.Config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.io.IOException;

public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {

    /**
     * context.refresh   初始化ApplicationContext的时候会回调这个方法
     * @param configurableListableBeanFactory
     * @throws BeansException
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

        try {

            //Spring工具类 读取类的源信息
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            //查找某个类上有没有加注解 第一个参数 某个类的类型  第二个参数 要找的注解
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if(componentScan!=null){
                for (String p:componentScan.basePackages()) {
                    System.out.println("包名:"+p);


                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();

                    //com.mangoubiubiu.show.a05.component
                    StringBuilder path = new StringBuilder();
                    path.append("classpath*:").append(p.replace(".","/")).append("/**/*.class");
                    System.out.println("拼接后的包名:"+path.toString());
                    //读取路径下的文件
        Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path.toString());
                    for (Resource res:resources) {
                        System.out.println("读取到的文件信息为:"+res);
                        MetadataReader reader = factory.getMetadataReader(res);
                        System.out.println("得到类信息:"+ reader.getClassMetadata().getClassName());
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
	System.out.println("是否加了Component注解"+ annotationMetadata.hasAnnotation(Component.class.getName()));
    System.out.println("是否加了Component注解 派生"+ annotationMetadata.hasMetaAnnotation(Component.class.getName()));

                        if(annotationMetadata.hasAnnotation(Component.class.getName()) || annotationMetadata.hasMetaAnnotation(Component.class.getName())){
                            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();

                            if (configurableListableBeanFactory instanceof DefaultListableBeanFactory  ) {
                                DefaultListableBeanFactory beanFactory = ((DefaultListableBeanFactory) configurableListableBeanFactory);
                                String beanName = generator.generateBeanName(beanDefinition, beanFactory);
                                beanFactory.registerBeanDefinition(beanName,beanDefinition);
                            }
                        }


                    }


                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

二、将ComponentScanPostProcessor 注入到容器里面

package com.mangoubiubiu.show.a05;

import com.mangoubiubiu.show.a05.component.ComponentScanPostProcessor;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.awt.*;
import java.io.IOException;

@Slf4j
public class A05Application {

    private MetadataReader reader;

    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();
        //将config注册到容器里面
        context.registerBean("config",Config.class);
        context.registerBean(ComponentScanPostProcessor.class);
//        context.registerBean(MapperScannerConfigurer.class,beanDefinition -> {
//            beanDefinition.getPropertyValues().add("basePackage","com.mangoubiubiu.show.a05.mapper");
//        });



        //初始化容器

        context.refresh();

        for (String name: context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        context.close();
    }



}

同理@Bean和@Mapper

Aware回调

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

为什么不用@Autowired

简单地说:
@Autowired 的解析需要用到 bean后处理器,属于扩展功能,而Aware接口属于内置功能,不加任何扩展,Spring就能识别某些情况下,扩展功能会失效,而内置功能不会失效

例2: Java配置类在添加了 bean 工厂后处理器后,你会发现用传统接口方式的注入和初始化仍然成功,而@Autowired 和@PostConstruct的注入和初始化失败

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

三种初始化方法

@PostConstruct

实现InitializingBean接口的afterPropertiesset()方法

@Bean(initMethod=“”)

执行顺序优先级从高到低

三种销毁方法

@PreDestroy

实现DisposableBean的destroy()

@Bean(destroyMethod=“”)

执行顺序优先级从高到低

五种Scope

在Java中,常见的五种Scope(作用域)是:

  1. Singleton(单例):在整个应用程序中只创建一个实例,所有对该类的引用都指向同一个对象实例。
  2. Prototype(原型):每次请求时都会创建一个新的实例,每个实例都是独立的。
  3. Request(请求):每个HTTP请求都会创建一个新的实例,在同一个请求中共享同一个实例,但不同请求之间的实例是独立的。
  4. Session(会话):每个用户会话(Session)期间只创建一个实例,在同一个用户会话中共享同一个实例,不同用户之间的实例是独立的。
  5. Application(应用):在整个Web应用程序的生命周期中只创建一个实例,所有用户共享同一个实例。

这些Scope主要用于Spring框架中的依赖注入管理,通过在Bean的定义中指定不同的Scope,控制对象的创建和共享方式。每种Scope都有其特定的使用场景和适用范围,可以根据需求选择合适的Scope来管理对象的生命周期和共享方式。

使用场景

  1. Singleton(单例):适用于需要在整个应用程序中共享和复用同一个实例的情况。比如,全局的配置对象、线程池、日志管理器等只需要一个实例来处理整个应用程序的请求。
  2. Prototype(原型):适用于每次请求都需要获得一个新的、独立的实例的情况。比如,每次请求都需要创建一个新的订单对象或邮件发送对象等,保证对象之间的隔离性。
  3. Request(请求):适用于每个HTTP请求需要获得一个新的实例,并且同一个请求中多个组件需要共享同一个实例的情况。比如,在Web应用程序中,不同组件需要访问同一个请求相关的数据或状态的场景。
  4. Session(会话):适用于需要在特定用户会话期间共享和保持同一个实例的情况。比如,保存用户登录状态、用户购物车等与特定用户相关联的数据的组件,确保同一个用户在同一个会话期间使用的是同一个实例。
  5. Application(应用):适用于需要在整个Web应用程序的生命周期中共享和保持同一个实例的情况。比如,全局的缓存对象、全局的应用程序状态等,确保整个应用程序共享的是同一个实例。

解决单例注入其他作用域

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

AOP

概念

AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它通过将横切关注点(Cross-cutting Concerns)从主体逻辑中分离出来,以模块化地实现跨多个部分的功能复用。

在传统的面向对象编程中,我们将程序的主要逻辑抽象为类和方法,但横切关注点(例如日志记录、事务管理、权限控制等)常常散布在整个应用程序中。这种散布导致了代码的重复性和难以维护性。而AOP的目标就是解决这个问题,通过将横切关注点与主体逻辑分离,使得关注点的修改和维护更加集中和方便。

AOP的核心概念包括:

  1. 切面(Aspect):切面是横切关注点的模块化,它定义了横切关注点的行为和逻辑。一个切面可以横跨多个类或模块,并在特定的连接点(Join Point)上执行自己的逻辑。
  2. 连接点(Join Point):连接点表示在程序执行过程中可以插入切面的位置,比如方法调用、方法执行前后、字段访问等。
  3. 通知(Advice):通知是切面在连接点上执行的动作,可以是在方法调用前后执行、方法抛出异常时执行等。
  4. 切点(Pointcut):切点是一组连接点的集合,它定义了那些连接点将被切面处理。
  5. 引入(Introduction):引入允许在不修改原有类的情况下,向现有类添加新的方法和属性。
  6. 织入(Weaving):织入是将切面应用到目标对象来创建新的代理对象的过程。织入可以在编译时、类加载时或运行时进行。

通过使用AOP,我们可以将关注点的代码从主体业务逻辑中分离出来,提高了代码的可重用性、可维护性和可理解性。常见的AOP框架有Spring AOP和AspectJ等。这些框架提供了强大的AOP功能和灵活的配置方式,使得我们能够更加方便地实现面向切面编程。

AOP示例和场景应用

以下是一个简单的AOP示例,使用Spring AOP框架进行切面编程:

假设我们有一个业务类UserService,其中有两个方法addUser()deleteUser()。我们希望在这两个方法执行前后记录日志。

首先,定义一个切面类LoggingAspect,用于实现日志记录逻辑:

javaCopy Codeimport org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.UserService.addUser(..)) || execution(* com.example.UserService.deleteUser(..))")
    public void beforeMethodExecution(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Before executing method: " + methodName);
    }

    @After("execution(* com.example.UserService.addUser(..)) || execution(* com.example.UserService.deleteUser(..))")
    public void afterMethodExecution(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("After executing method: " + methodName);
    }
}

切面类LoggingAspect使用了@Aspect@Component注解,表示它是一个切面,并且可以被Spring自动扫描和注册为Bean。

在切面类中定义了两个通知方法beforeMethodExecutionafterMethodExecution,分别在目标方法执行前和执行后执行。这里通过@Before@After注解来指定切入点表达式,对UserService类的addUser()deleteUser()方法进行拦截。

接下来,在Spring配置文件中进行相关的配置:

xmlCopy Code<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 扫描切面类 -->
    <bean class="com.example.LoggingAspect" />

    <!-- 启用AOP支持 -->
    <aop:aspectj-autoproxy />
    
    <!-- 其他配置 -->

</beans>

在配置文件中,我们使用<bean>标签来注册切面类LoggingAspect,并使用<aop:aspectj-autoproxy>标签启用AOP支持。

最后,在UserService类中调用目标方法:

javaCopy Codepackage com.example;

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public void addUser(String username) {
        System.out.println("Adding user: " + username);
    }

    public void deleteUser(String username) {
        System.out.println("Deleting user: " + username);
    }
}

现在,当调用UserServiceaddUser()deleteUser()方法时,切面类LoggingAspect的通知方法会在方法执行前后被触发,实现了日志记录的功能。

注意:上述示例中使用了Spring框架的AOP支持,因此需要依赖相关的Spring库,并将配置文件与项目正确关联。如果想使用纯AspectJ框架,可以参考AspectJ的官方文档进行配置和使用。

切入点表达式

execution(* com.example.UserService.addUser(..))是一个切入点表达式,用于匹配目标方法的执行。下面是该表达式的详细解释:

  • execution: 表达式的起始关键字,表示匹配方法的执行。
  • *: 通配符,表示匹配任意返回类型的方法。
  • com.example.UserService: 表示包名为com.example,类名为UserService的类。
  • addUser: 表示要匹配的方法名为addUser
  • (..): 表示方法参数的匹配规则。这里的(..)表示匹配任意个数、任意类型的参数。

因此,execution(* com.example.UserService.addUser(..))的含义是:匹配任意返回类型、在com.example.UserService类中名为addUser的方法,并且方法参数可以是任意个数、任意类型。

这个切入点表达式可以用于AOP中的注解、XML配置或者编程方式进行切入点的定义。它告诉AOP框架,在目标方法执行前后触发切面逻辑。如果需要匹配其他方法或修改匹配规则,可以根据实际情况进行相应的修改。

ajc编译器

@Aspect

在使用@Aspec注解时,并不会被spring动态代理,而是直接修改class文件,通过ajc编译器就可以直接实现方法增强

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

agent增强

通过jvm设置参数,在类加载阶段通过修改类的字节码做到增强

ps:可以通过阿里的arthas工具来反编译类加载阶段的class

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端JDK代理

只针对接口代理,代理平级,实现共同接口

JDK代理(JDK Proxy)是Java中的一种动态代理机制,它基于接口实现。Java提供了一个java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口,用于创建动态代理对象并处理方法调用。

使用JDK代理,需要满足以下条件:

  1. 目标类必须实现一个或多个接口。
  2. 创建一个实现InvocationHandler接口的代理处理器类,该处理器类负责真正的代理逻辑。
  3. 使用Proxy.newProxyInstance()方法创建代理对象,该方法接受目标类的ClassLoader、接口数组和代理处理器作为参数。

下面是一个简单的示例:

javaCopy Codeimport java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

interface MyInterface {
    void doSomething();
}

class MyTargetClass implements MyInterface {
    public void doSomething() {
        System.out.println("Doing something...");
    }
}

class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method invocation");
        Object result = method.invoke(target, args);
        System.out.println("After method invocation");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        MyInterface targetObject = new MyTargetClass();
        InvocationHandler invocationHandler = new MyInvocationHandler(targetObject);
        MyInterface proxyObject = (MyInterface) Proxy.newProxyInstance(
                targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(),
                invocationHandler);

        proxyObject.doSomething();
    }
}

在上面的示例中,MyInterface 是一个接口,MyTargetClass 是实现了该接口的目标类。MyInvocationHandler 是代理处理器类,它实现了InvocationHandler接口,负责在方法调用前后添加额外逻辑。在Main类的main方法中,通过Proxy.newProxyInstance()方法创建了一个代理对象proxyObject,并对MyInterface接口的方法调用进行了拦截和处理。

总之,JDK代理是一种基于接口的动态代理机制,使用JDK提供的Proxy类和InvocationHandler接口,可以在运行时创建代理对象,并在方法调用前后添加额外逻辑。

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端

CGLIB代理

代理子,目标父,目标类不能finnal修饰报错,finnal修饰的方法也不能增强

默认情况下,Spring AOP 使用 CGLIB(Code Generation Library)作为代理机制。CGLIB是一个强大的基于字节码生成的开源库,它能够在运行时动态地创建目标对象的子类,并覆盖其中的方法以实现切面逻辑。

当目标对象没有实现任何接口时,Spring AOP 将使用 CGLIB 代理。这样可以在运行时生成一个继承自目标对象的子类,并将切面逻辑织入到子类中。在运行时,通过代理对象调用方法时,会先执行切面逻辑,然后再调用目标方法。

但是如果目标对象实现了接口,Spring AOP 也可以选择使用 JDK 动态代理(Java Dynamic Proxy)作为代理机制。JDK 动态代理是 Java 标准库中提供的一种代理方式,通过实现目标对象实现的接口,在运行时生成代理对象,并将切面逻辑织入到代理对象的方法中。

可以通过配置来强制使用CGLIB代理或者JDK动态代理。例如,可以使用<aop:config>配置元素的 proxy-target-class 属性来指定是否使用CGLIB代理。

xmlCopy Code<aop:config proxy-target-class="true">
    <!-- 配置切面和通知 -->
</aop:config>

总之,Spring AOP 默认使用 CGLIB 作为代理机制,但也可以根据情况自动选择使用 JDK 动态代理。

【Spring源码】小白速通解析Spring源码,从0到1,持续更新!,spring,java,后端文章来源地址https://www.toymoban.com/news/detail-657782.html

到了这里,关于【Spring源码】小白速通解析Spring源码,从0到1,持续更新!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【笔记】Spring Boot 历史官方文档学习(持续更新)

    Spring Boot 2014正式发布1.0版本,距今已经快10年了。看历史官方文档了解重点feature, 帮助自己建立知识网络。 与 Spring 5 官网历史文档学习 一样,尽量保证不误解文档作者的原意,不好翻译的会有原文摘录(包括一些专有名词),并辅以自己的理解。限于篇幅原因,只摘录工作

    2024年02月10日
    浏览(47)
  • java spring cloud 企业电子招标采购系统源码:营造全面规范安全的电子招投标环境,促进招投标市场健康可持续发展

    功能描述 1、门户管理:所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含:招标公告、非招标公告、系统通知、政策法规。 2、立项管理:企业用户可对需要采购的项目进行立项申请,并提交审批,查看所有的立项信息。主要功能包含:招标立项申

    2024年02月08日
    浏览(54)
  • Spring Boot 集成 WebSocket 实例 | 前端持续打印远程日志文件更新内容(模拟 tail 命令)

    这个是我在 CSDN 的第一百篇原则博文,留念😎 先说下项目结构,后端基于 Spring Boot 3,前端为 node.js 开发的控制台程序。现在希望能够在前端模拟 tail 命令,持续输出后端的日志文件。 这个方案实施较为简单,通过前端不断(定时)发起请求,并携带已读的内容坐标(posi

    2024年03月18日
    浏览(46)
  • 【Spring】Spring之事务底层源码解析

    能使用spring事务解决开发需求 了解spring事务是如何被spring管理的 了解spring事务底层原理实现,比如代理、事务传播机制等 配置数据源及事务管理器: 业务逻辑代码: 调用: 结果: 如上,就是Spring中事务的简单应用,接下来分析Spring事务的实现原理。 开启Spring事务本质上

    2024年02月14日
    浏览(40)
  • 【Spring】Spring之AOP底层源码解析

    理解Spring中AOP的实现原理 Spring中有关AOP功能的使用 什么是动态代理: 为 其他对象 提供一种 代理 以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。 如下一个service类,如果想不改变test方法代码的情况下,增加特定的逻辑,该怎么做呢? 此时就可以用

    2024年02月14日
    浏览(41)
  • Spring源码(二)Spring底层架构核心概念解析

    BeanDefinition表示 Bean定义 ,BeanDefinition中存在很多属性用来描述一个Bean的特点。比如: class,表示Bean类型 scope,表示Bean作用域,单例或原型等 lazyInit:表示Bean是否是懒加载 initMethodName:表示Bean初始化时要执行的方法 destroyMethodName:表示Bean销毁时要执行的方法 在Spring中,我

    2024年02月15日
    浏览(35)
  • 【Spring】Spring之Bean生命周期源码解析

    什么是bean的生命周期 是指bean在spring中是如何生成,如何销毁的; spring创建对象的过程,就是IOC(控制反转)的过程; JFR Java Flight Record,java飞行记录,类似于飞机的黑匣子,是JVM内置的基于事件的JDK监控记录框架,主要用于问题定位和持续监控; 入口代码: Spring启动的时

    2024年02月15日
    浏览(46)
  • 【框架源码】Spring源码解析之BeanDefinition加载流程解析

    观看本文之前,我们先思考一个问题,Spring是如何描述Bean对象的? Spring是根据BeanDefinition来创建Bean对象,BeanDefinition就是Spring中表示Bean定义。BeanDefinition用来存储Bean的相关信息,主要包括:Bean的属性、是否单例、延迟加载、Bean的名称、构造方法等。 简言之就是Spring通过解

    2024年02月09日
    浏览(44)
  • Spring源码解析

    下载 下载gradle 因为Spring源码里没有使用Maven依赖,而是使用gradle依赖,所以我们需要在本地下载安装并配置gradle环境。注意,这里下载安装的gradle版本应与Spring源码中的gradle版本对应。这里推荐下载我的: 链接: https://pan.baidu.com/s/1YVww-x7Furqq3s0KcN27CQ 提取码: 6ai4 下载Spring源码

    2024年02月06日
    浏览(25)
  • Spring事件监听源码解析

    spring事件监听机制离不开容器IOC特性提供的支持,比如容器会自动创建事件发布器,自动识别用户注册的监听器并进行管理,在特定的事件发布后会找到对应的事件监听器并对其监听方法进行回调。Spring帮助用户屏蔽了关于事件监听机制背后的很多细节,使用户可以专注于业

    2024年02月12日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包