Spring AOP源码分析(二)【组件注册】

一、Springboot AOP自动装配原理

  • 了解Springboot自动装配原理的同学一定会知道,Springboot在启动容器的时候会去扫描所有jar包类路径下 META‐INF/spring.factories 文件,然后会把把扫描到的这些文件的内容包装成properties对象,从properties中获取到EnableAutoConfiguration类对应的值,然后把他们添加到Spring容器中【不了解也没关系,后续博客会陆续更新Springboot自动配置相关的知识】。
  • 本次AOP源码分析我使用的Springboot版本是2.1.3.RELEASE,需要看源码的同学请到上一篇博客【Spring AOP源码分析(一)】中获取。下面我们来看一下Springboot自动装配文件中装载的信息。
    在这里插入图片描述
  • 根据自动装配文件中配置的数据,我们可以很清楚的看到Spring AOP的自动装配类为AopAutoConfiguration,其源码如下:
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
/**
 * prefix:配置文件中的前缀
 * name:配置的名字
 * havingValue:havingValue是与配置的值对比值,当两个值相同返回true,配置类生效。
 * matchIfMissing:matchIfMissing = true表示如果没有在application.properties设置该属性,则默认为条件符合
 */
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
    
    // AOP动态代理---》JDK动态代理方式(需要有接口方式进行代理)
    @Configuration
    @EnableAspectJAutoProxy(proxyTargetClass = false)
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
    public static class JdkDynamicAutoProxyConfiguration {}

    // AOP动态代理---》Cglib代理方式(不需要接口,以子类方式,但是无法代理final方法),根据@ConditionalOnProperty注解
    // 可以看出,Spring自动配置AOP时默认采用Cglib的方式代理
    @Configuration
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
    public static class CglibAutoProxyConfiguration {}
}

  1. @Configuration 说明这是一个配置类
  2. @ConditionalOnClass 当前classpath下面,有EnableAspectJAutoProxy、Aspect、Advice、AnnotatedElement 这几个类才会去加载该类,通俗说就是有spring-aop 依赖才会加载。
  3. @ConditionalOnProperty 在上一步的基础上,再一步对配置进行条件判断,即判断是否有spring.aop.auto=true 配置,若有则开启配置(设置为false会关闭自动配置)。matchIfMissing = true表示,如果没有在application.yml设置该属性,则默认为条件符合。
  4. 配置类中的两个子配置类JdkDynamicAutoProxyConfiguration 、CglibAutoProxyConfiguration 为SpringAop的两种代理方式,根据其标注的@ConditionalOnProperty注解信息可以看出,如果Spring没有显示的在application.yml中指定那种代理方式时,系统会默认采用Cglib代理的方式。

二、AOP核心组件注册原理

  • EnableAspectJAutoProxy 这个注解是AopAutoConfiguration 的两个子配置类共有的注解(Spring注册子配置类时会注册这个注解)。这个注解除了两个属性外,还使用了@Import注解向容器中引入了AspectJAutoProxyRegistrar 类,这个类实现了ImportBeanDefinitionRegistrar接口,然后通过这个接口向Spring容器中注册了AnnotationAwareAspectJAutoProxyCreator 类的BeanDefinition信息(Spring容器刷新的时候会根据BeanDefinition创建对应的类),这个类接下来将是我们研究的重点了,我们先来看一下这个类是怎么通过EnableAspectJAutoProxy注解注册到Spring容器中的。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 使用@Import注解注册AspectJAutoProxyRegistrar类
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    
    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;
}
  • AspectJAutoProxyRegistrar类
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        // 向容器中注册AnnotationAwareAspectJAutoProxyCreator的BeanDefinetion信息
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		// 获取@EnableAspectJAutoProxy注解的属性信息
        AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
        	// 如果proxyTargetClass属性为true,强制使用Cglib代理模式
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }
}
  • AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary()
.....AopConfigUtils类.....

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
	return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, @Nullable Object source) {
	// 返回注册AnnotationAwareAspectJAutoProxyCreator的BeanDefinition对象
	return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
        Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

    // BeanDefinitionRegistry中是否已经注册了该组件,初始化时显然这里是没有创建的
    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
        BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            int requiredPriority = findPriorityForClass(cls);
            if (currentPriority < requiredPriority) {
                apcDefinition.setBeanClassName(cls.getName());
            }
        }
        return null;
    }
    // 将传入的AnnotationAwareAspectJAutoProxyCreator封装为beanDefinition,Spring容器初始化的时候会装载该组件
    RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    beanDefinition.setSource(source);
    // 设置优先级
    beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    // 定义AnnotationAwareAspectJAutoProxyCreator组件在Spring容器中的别名
    // 我们可以通过这个名字从Spring容器中获取该组件,类似于xml配置中指定的标签id
    registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    return beanDefinition;
}

到这里我们已经知道了AnnotationAwareAspectJAutoProxyCreator的BeanDefinition信息是如何被注册到Spring容器中的了,其实大家还是会对AspectJAutoProxyRegistrar类的加载时机存在疑问的,那接下来我们大致的分析一下AspectJAutoProxyRegistrar的加载流程。

  1. 首先我们进入到Spring Ioc容器启动的核心方法AbstractApplicationContext#refresh()方法,其定义如下:
public void refresh() throws BeansException, IllegalStateException {

   synchronized (this.startupShutdownMonitor) {
      // 记录容器的启动时间、标记“已启动”状态、检查环境变量
      prepareRefresh();
      // 初始化BeanFactory容器(DefaultListableBeanFactory)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
      prepareBeanFactory(beanFactory);
      try {
         // 扩展点,具体逻辑由子类去实现
         postProcessBeanFactory(beanFactory);
         // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
         invokeBeanFactoryPostProcessors(beanFactory);
         // 注册 BeanPostProcessor 的实现类
         registerBeanPostProcessors(beanFactory);
         // 初始化MessageSource
         initMessageSource();
         // 初始化事件广播器
         initApplicationEventMulticaster();
         // 扩展点,交由子类实现
         onRefresh();
         // 注册事件监听器
         registerListeners();
         // 初始化所有的 singleton beans
         finishBeanFactoryInitialization(beanFactory);
         // 广播事件
         finishRefresh();
      }catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }
         // 销毁已经初始化的的Bean
         destroyBeans();
         // 设置 'active' 状态
         cancelRefresh(ex);
         throw ex;
      }finally {
         // 清除缓存
         resetCommonCaches();
      }
   }
}
  1. 这里我们重点关注invokeBeanFactoryPostProcessors(beanFactory)方法,该方法会调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法;这其中包含了一个重要的后置处理器ConfigurationClassPostProcessor,这个后置处理器会解析加了@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import等注解。在我们前面的分析中,我们可以清晰的看到AspectJAutoProxyRegistrar类是通过@Import注解导入的,那我们通过源码来分析一下流程吧。

refresh()#invokeBeanFactoryPostProcessors方法

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	// 调用并执行实现了BeanFactoryPostProcessor接口的子类的postProcessBeanFactory(factory)方法
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

这里我们要详细的看一下invokeBeanFactoryPostProcessors()方法的执行,该方法会调用ConfigurationClassPostProcessor类后置处理方法,后置处理方法会去解析并调用AspectJAutoProxyRegistrar类,并将AnnotationAwareAspectJAutoProxyCreator的BeanDefinition信息注册到容器中。接下来我们看一下ConfigurationClassPostProcessor后置处理器的继承关系图:
在这里插入图片描述

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    Set<String> processedBeans = new HashSet<>();
    // 首先执行实现了BeanDefinitionRegistryPostProcessors后置处理器的组件
    if (beanFactory instanceof BeanDefinitionRegistry) {
        // BeanDefinition注册管理器,托管了所有的BeanDefinition信息
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // 保存常规BeanFactoryPostProcessor
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        // 保存BeanDefinitionRegistryPostProcessor
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
        /**
         * 遍历所有传进来的BeanFactoryPostProcessor,并其将分成两组 :
         * BeanDefinitionRegistryPostProcessor 和常规 BeanFactoryPostProcessor
         * 1.如果是BeanDefinitionRegistryPostProcessor,现在执行postProcessBeanDefinitionRegistry(),
         * 2.否则记录为一个常规 BeanFactoryPostProcessor,现在不执行处理
         */
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            } else {
                regularPostProcessors.add(postProcessor);
            }
        }

        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        // 从BeanFactory中获取实现了BeanDefinitionRegistryPostProcessor接口的组件,这里我们关心的是ConfigurationClassPostProcessor
        // ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口
        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
        // 根据是否实现了PriorityOrdered、Ordered接口进行排序
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        // 执行后置处理器的后置处理方法,接下来我们重点分析这个方法的调用链
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();
        ......省略非必要代码.........
    }
}

/**
 * Invoke the given BeanDefinitionRegistryPostProcessor beans.
 */
private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
    for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
    	// 调用实现类的postProcessBeanDefinitionRegistry后置处理方法,最终调用到
    	// AspectJAutoProxyRegistrar的registerBeanDefinitions方法,实现AOP相关的组件注册,具体的细节就交由各个同学自己去分析了
        postProcessor.postProcessBeanDefinitionRegistry(registry);
    }
}

到这里我们的组件就完成了,接下来我们将会去分析AnnotationAwareAspectJAutoProxyCreator类怎样去增强我们需要增强的类,谢谢大家的观看。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值