【Spring源码解读】SpringAOP源码

Source

BeanPostProcessor及其家族成员

image-20220113200410232

InstantiationAwareBeanPostProcessor

这三个方法覆盖Bean实例化的前后过程以及Bean的属性设置

在Bean的实例化过程中(实例化是在Bean初始化之前并且也是在附上属性之前)给Bean去加上额外的逻辑。

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    
      
    
    //用来在对象实例化前直接返回一个对象(如代理对象)来代替通过内置的实例化流程创建对象
	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    
      
		return null;
	}
    
    //在对象实例化完毕执行populateBean之前 如果返回false则spring不再对对应的bean实例进行自动依赖注入
	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    
      
		return true;
	}
    
    //这里是在spring处理完默认的成员属性,应用到指定的bean之前进行回调,可以用来检查和修改属性,最终返回的PropertyValues会应用到bean中
	//@Autowired、@Resource等就是根据这个回调来实现最终注入依赖的属性的。
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {
    
      

		return null;
	}
    

SmartInstantiationAwareBeanPostProcessor

主要作用在Bean实例化过程中的

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
    
      
    
    //预测bean的类型   用来返回目标对象的最终类型(比如代理对象通过beanClass获取proxy type)
	@Nullable
	default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
    
      
		return null;
	}
    
    //选择合适的构造器   提供一个拓展点用来解析获取用来实例化的构造器(比如未通过bean定义构造器以及参数的情况下,会根据这个回调来确定构造器)
	@Nullable
	default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
			throws BeansException {
    
      

		return null;
	}
    
    //循环依赖注入   获取要提前暴露的bean的引用,用来支持单例对象的循环引用(一般是bean自身,如果是代理对象则需要取用代理引用)
	default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
    
      
		return bean;
	}

研究SpringAOP源码

为什么在启动类加上@EnableAspectJAutoProxy就能支持AOP?

通过注解将类当做Bean管理起来的方式

◆@Controller @Service @Repository @Component标记的类
◆@Bean标记的方法

◆@Import标签

image-20220114142659372

image-20220114143356394

SpringAOP的总体流程

◆注册解析AOP的服务
◆解析和加载横切逻辑
◆将横切逻辑织入目标Bean中

◆注册解析AOP的服务

AnnotationAwareAspectJAutoProxyCreator的BeanDefinition是在IoC容器初始化的时候,也就是在执行refresh方法进行刷新的时候通过BeanDefinitionRegistryPostProcessor类型的容器级别的后置处理器方法postProcessBeanDefinitionRegistry进行注册的。

image-20220114151324142

spring独有的Advisor术语含义:

Advisor下面只是有一个pointcut和advice,不像我们前面的ServiceAspect可以有多个pointcut和多个advice,我们spring AOP在处理横切逻辑时会在ServiceAspect这里将aspect转换为多个Advisor。将Aspect里面的pointcut和advice给一一对应起来。

public interface Advisor {
    
      

image-20220114150745302

Aspect和Advice的加载阶段

因为在后续创建动态代理的时候,需要拿着所有Asepct与容器的业务bean去做匹配,之后匹配了的Aspect,我们才会去做动态代理。进行匹配前势必要将IoC容器所有的aspect和对应的advice都加载好并缓存起来,随后才可以遍历所有的横切逻辑实例去做相关的匹配工作。

spring主要依靠BeanPostProcessor、InstantiationAwareBeanPostProcessor、SmartInstantiationAwareBeanPostProcessor接口里面的后置处理器方法来介入spring IoC容器的bean实例化和初始化的过程中,对bean进行aop处理的。

横切逻辑的加载主要在AbstractAutoProxyCreator的postProcessBeforeInstantiation里,该方法是在bean实例化之前被调用的

AnnotationAwareAspectJAutoProxyCreator:只支持获取被注解标记的切面类,为了支持被接口实现的切面类配置和xml配置的切面类进行解析,还需要复用父类的能力。

分析切面类加载以及通知方法的加载栈过程

image-20220114170217675

image-20220114170124826

image-20220114175251307

image-20220114174618997

在spring容器首次触发bean的创建时就会开始aspect的解析,相关的解析是在真正调用doCreatBean方法之前去执行的,即在AbstractAutoProxyCreator的postProcessBeforeInstantiation方法里,里面相关的解析逻辑就包含在shouldSkip方法里。shouldSkip方法会调用findCandidateAdvisors方法去解析aspect切面,并合并解析出来的注解和非注解的advisors。而针对注解的Aspect来讲,对应的Advice是通过buidAspectJAdvisors解析出来的,将Advices解析出来之后,会以Aspect的名字作为key,对应的Advices列表为v存入缓存以供下次使用。

筛选匹配的横切逻辑实例(对目标bean织入横切逻辑的过程)

实例化----》初始化invokeInitMethods(bean创建完成)—》将相关的横切逻辑给织入到bean里

通过bean级别的后置处理器在bean的生命周期中对bean进行处理的,而针对bean初始化完成再介入的点就不是很多了。spring AOP通过applyBeanPostProcessorsAfterInitialization方法的postProcessAfterInitialization对bean进行横切逻辑的织入。

image-20220115105458992

image-20220115110038879

image-20220115113038061 image-20220115112934789

走完流程之后,取消上面的所有断点,看看收集到的结果

image-20220115113416676

创建动态代理

适配器模式:

主要将类的接口转换为所期待的另外一种接口,从而使得应原本接口不匹配而无法在一起工作的两个类能够在一起工作

image-20220116113140219

AbstractAdvisorAutoProxyCreator在创建动态代理前,总会对Advisor进行筛选(即调用findEligibleAdvisors方法去筛选匹配被代理bean的Advices),

创建动态代理

proxyFactory.getProxy(getProxyClassLoader());

本章小结

image-20220116141717200

image-20220116141741562

从动态代理创建器AbstractAutoProxyCreator的注册、切面逻辑的加载与解析、以及动态代理的织入三个方法分析spring的整个脉络。

先是以Bean级别的后置处理器的执行时机分析,SpringAOP通过实现SmartInstantionAwareBeanPostProcessor及其父类接口的方法来将自身得逻辑融入的bean实例化、属性赋值以及初始化的过程当中,上述后置处理器的实现类正是先前多次接触的AbstractAutoProxyCreator。

再以容器启动类的@Import标签为切入点去分析AnotationAwareAspectJAutoProxyCreator的注册流程。该类是在容器刷新的时候,即在执行容器级别的BeanDefinitionRegistry的postProcessBeanDefinitionRegistry方法时被注册进来。

在真正创建动态代理之前,springAop会扫描整个容器解析并加载容器里面的切面类,将其转换成一个个advisor实例,并添加到容器的缓存里。整个过程是在instatiationAwareBeanPostProcessor里面的postProcessBeforeinstantiation方法被执行的时候,即首次调用doCreateBean方法,对bean进行真正创建之前进行的。在这里主要分析了注解@Aspect的解析和加载过程,接着有了解析出来的Advisors,我们就能去便利容器当中的bean,并依据AspectJ表达式筛选出需要进行横切逻辑织入的bean及其对应的Advices,通过CgLiB或者动态代理的方式创建出bean对应的动态代理实例来。这一步是在BeanPostProcessor里面的postProcessAfterInitialization方法里面被执行的,会针对每个bean进行Advisors的筛选以及动态代理的生成,最后在被目标代理bean的方法被触发的时候就会通过调用链去按序递归执行织入的横切逻辑以及被代理的方法。