Spring——AOP之全注解源码探查
每天进步一点点,大家好,我是大龄码农。
今天我们聊聊Spring是如何使用注解来完成AOP功能的
在开始之前,我们要明确一件事,Spring最先是使用xml配置的,后来才使用注解。那么,在保证Spring整体流程不做大的改动的前提下,如果要引入注解,Spring最应该做的事情是什么?
大家应该还记得,在前面的源码探查系列中,使用xml配置时,Spring对于不同的标签会有相应的解析器,作用就是将xml配置的内容转换为BeanDefinition对象。那么,使用注解配置时,Spring要做的无非就是想办法将注解标识的类转换成BeanDefinition对象。
那么,我们就用以下这个程序,来看看Spring是如何处理注解的

说明:对注解不太熟悉的同学,猛戳这里
其实,对于上面的程序来说,下面的写法可能会更清晰一些

说明:使用@Pointcut标注一个方法
一、注解
1、@Aspect
这是AspectJ的注解,代表这个类是一个切面
2、@EnableAspectJAutoProxy
启用AspectJ的注解支持,使用xml的配置就是<aop:aspectj-autoproxy/>标签
注:这个注解写在这个类上,其实不太合适。

说明:这个注解引入了AspectJAutoProxyRegistrar类

说明:先记住这个类的继承关系,一会儿再介绍
二、处理过程

说明:在测试类时使用的是AnnotationConfigApplicationContext类的这个构造函数

说明:和ClassPathXmlApplicationContext一样,它也是AbstractApplicationContext的一个实现类
1、this()

说明:这里初始化两个类
1)AnnotatedBeanDefinitionReader
代码一路点进去,进入到registerAnnotationConfigProcessors()方法

说明:这个方法由两部分构成
-
设置DefaultListableBeanFactory的属性
-
手动注册PostProcessor
a、ConfigurationClassPostProcessor

说明:它是BeanFactoryPostProcessor的实现类,所以会在invokeBeanFactoryPostProcessors(beanFactory)方法中触发postProcessBeanFactory()方法
b、AutowiredAnnotationBeanPostProcessor

说明:它是BeanPostProcessor的实现类,所以在对象属性初始化的前后都会调用相应的方法
c、CommonAnnotationBeanPostProcessor

说明1:它是BeanPostProcessor的实现类,也是InitDestroyAnnotationBeanPostProcessor的实现类,也就是说,在方法初始化前后以及对象销毁前都会调用相应的方法
说明2:这个类存在的前提是当前有javax.annotation.Resource类
d、PersistenceAnnotationBeanPostProcessor
用于注入持久化信息,相应的JPA资源是EntityManagerFactory和EntityManager

说明:这个类存在的前提是当前有javax.persistence.EntityManagerFactory类
e、EventListenerMethodProcessor

说明:与Spring事件相关,后续会介绍
f、DefaultEventListenerFactory

说明:与Spring事件相关,后续会介绍
小结:在AnnotatedBeanDefinitionReader里,主要目的就是注册几个BeanPostProcessor
2)ClassPathBeanDefinitionScanner
一路点击,进入到ClassPathBeanDefinitionScanner()方法

说明:这里先关注registerDefaultFilters()方法

说明:待过滤的默认注解,首当其冲的就是Component注解,
小结:在ClassPathBeanDefinitionScanner里,主要目的就是定义要过滤的注解
2、scan(basePackages)
一路点击,来到如下方法

说明1:方法入参是可变参数,所以可以传入多个
说明2:这里调用了registerAnnotationConfigProcessors()方法,可能感觉是重复了,其实是因为调用的入口不同所致,但是Spring要保证在处理前注册那几个PostProcessor


说明:这里简单说下doScan()方法
a、findCandidateComponents()
找到候选类,即过滤提前定义好的注解的类,这个方法包含两个步骤
-
通过递归找到包下面的所有class文件
-
对于找到的class文件,再筛选符合条件的class文件
b、postProcessBeanDefinition()
查看是否有定义autowireCandidatePatterns,通过正则表达式定义一组模式,这些模式将匹配的bean视为自动装配的候选者。在大型项目中特别有用。在xml配置中,使用<context:include-filter>标签
c、processCommonDefinitionAnnotations()
处理一些通用注解和属性,比如:Primary和Lazy
d、AnnotationConfigUtils.applyScopedProxyMode()
用于处理Scope注解,判断是否要使用作用域代理,默认不使用。作用域代理一般用于如下情况:如果A依赖B,并且B的作用域范围是小于A的作用域范围时,正常情况下,那么B的生命周期会变成与A的生命周期一致。如果不想要改变B的生命周期,就需要使用作用域代理来解决。
实现方式还是差不多的,JDK代理也好,CGLIB代理也好,使用的类是

3、refresh()
这个方法不能再陌生一点儿了吧,它就是整体的处理流程。下面我们就一些不同点简单说一下
a、obtainFreshBeanFactory()
这里调用的是两个方法都是来自于GenericApplicationContext类,但是实际上没有做什么
注:另一个子类AbstractRefreshableApplicationContext就做了一些事,最主要的就是通过loadBeanDefinitions()方法将xml标签解析成对应的BeanDefinition对象
b、invokeBeanFactoryPostProcessors()
一路点进去,来到invokeBeanFactoryPostProcessors()方法

说明:还记得ConfigurationClassPostProcessor类吗,它是BeanDefinitionRegistryPostProcessor的子类,所以,以前没有走过的分支如今就要走一走了

说明:进入到processConfigBeanDefinitions()方法,关于排序什么的就不说了,直接到达这里

说明:虽然注释是解析Configuration注解,但是这里包括Component注解

说明:因为Configuration是被Component注解的注解

说明:进入到parse()方法,肯定进入第一个判断分支

说明1:parse()方法调用XXX()方法,XXX()方法调用doXXX()方法
说明2:在doProcessConfigurationClass()方法中,主要处理了如下注解:Component、PropertySources、ComponentScan、Import、ImportResource、Bean等

说明:这里介绍下对Import注解的处理

说明:这是filter的定义

说明:会走这个分支,因为AspectJAutoProxyRegistrar是ImportBeanDefinitionRegistrar的实现类。创建对象后,被加入到名为importBeanDefinitionRegistrars的LinkedHashMap中

说明:从方法出来后,继续向下执行到loadBeanDefinitions()方法,看名字就应该知道它要将注解类转换为BeanDefinition对象了。一路进入到



说明1:使用AnnotationAwareAspectJAutoProxyCreator类注册一个名为”org.springframework.aop.config.internalAutoProxyCreator”的BeanDefinition
说明2:解析EnableAspectJAutoProxy注解,判断是否要给说明1中的BeanDefinition增加属性值

说明:这是AnnotationAwareAspectJAutoProxyCreator类的继承图
小结:因为ConfigurationClassPostProcessor类是BeanDefinitionRegistryPostProcessor的子类,所以在创建Bean对象前对BeanDefinition进行操作,主要目的就是解析注解,并转换成BeanDefinition对象。
三 、创建容器对象
其实创建流程与以前一样,只是使用的实现类不一样,简单说一下,现在大家都知道,AbstractAutoProxyCreator#postProcessAfterInitialization()是创建代理的重要方法。
其中isInfrastructureClass()方法,以及在AbstractAdvisorAutoProxyCreator#findEligibleAdvisors()方法中调用findCandidateAdvisors()方法时,调用的都是AnnotationAwareAspectJAutoProxyCreator类提供的实现方法
关于获取对象和执行目标方法和之前说的一样,这里就不再赘述了。
这次之所以聊全注解的源代码,主要原因在于:
-
了解Spring是如何处理注解的 -
为未来打基础
夜雨聆风