文章目录
Aop 源码分析
一、主要类
1.1 @EnableAspectJAutoProxy
- @EnableAspectJAutoProxy注解做了什么事情?想要开启Aop功能我们需要使用该注解,源码如下,我们先关注@Import(AspectJAutoProxyRegistrar.class),这说明开启了该注解的情况下,会往IOC容器中注入AspectJAutoProxyRegistrar这么一个Bean,我们从这里开始分析探究。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
* 默认false,采用JDK动态代理织入增强(实现接口的方式);如果设为true,则采用CGLIB动态代理织入增强
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
* 默认false,设置为true意味着proxy代理会暴露到AOP框架之外,但是并不保证通过AopContext访问使用是正确的
*/
boolean exposeProxy() default false;
}
1.2 AspectJAutoProxyRegistrar
- 前面提到@EnableAspectJAutoProxy注解会将注册一个AspectJAutoProxyRegistrar类型的bean,我们看看其源码。AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,因此它能够往容器中自定义注册Bean,逻辑都在registerBeanDefinitions方法里面,究竟注册了什么?我们debug来看看
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
/**
*我们看到方法名称的含义是在需要的情况下注册一个切面代理(大概这个意思吧)
*我们推测注册逻辑是在这个方法里面,跟进。
*/
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
1.2.1 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary
- 我们先看方法跟进,方法会一直调用到最后的registerOrEscalateApcAsRequired
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
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");
//1.判断是否已经注册了一个bean定义信息,名字是 AUTO_PROXY_CREATOR_BEAN_NAME ="org.springframework.aop.config.internalAutoProxyCreator"
//第一次肯定没有,因此这个逻辑第一次会跳过
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;
}
//2.根据传进来的类创建beanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
//3.设置相关属性
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//4.注册beanDefinition,bean的名称是"org.springframework.aop.config.internalAutoProxyCreator"
//之后容器中会注册一个AnnotationAwareAspectJAutoProxyCreator.class类型的bean,beanName为org.springframework.aop.config.internalAutoProxyCreator
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
//5.这里返回值不重要,关键是第四步骤注册bean定义
return beanDefinition;
}
- 到此我们明白了,我们使用@EnableAspectJAutoProxy注解其实最核心的是注册了一个AnnotationAwareAspectJAutoProxyCreator.class类型的bean,其名称是org.springframework.aop.config.internalAutoProxyCreator,那么我们后续探究AOP的关键点就是这个Bean了,主要是探究它的工作机制(其实其他功能也是一样,我们要摸清其组件和组件工作机制)。
二、AnnotationAwareAspectJAutoProxyCreator
- AnnotationAwareAspectJAutoProxyCreator几乎是实现AOP最为核心的一个类。
2.1 继承关系
[外链图片转存失败(img-dPPBng37-1569065835582)(https://note.youdao.com/yws/api/personal/file/BD8FA85560E24E13B2F0A20659E89363?method=download&shareKey=2da8f90e6e9d4bb7c32079c30a15520a)]
- 我们看到AnnotationAwareAspectJAutoProxyCreator它继承了实现了SmartInstantiationAwareBeanPostProcessor和BeanFactoryAware这两个很关键的接口,前者实际上是增强了的BeanPostProcessor(InstantiationAwareBeanPostProcessor),因此这个类的功能会非常多,我们慢慢来看。
2.2 注册流程
- 在08-spring Bean生命周期详细图解中给出了普通bean生命周期详细图解,时间上处理器bean的流程也类似,不过时机更早,在代码上类似于BeanPostProcessor,这里可以参考03-spring BeanPostProcessor,这里的分析集假定我们已经知道前面2篇文章了。
AbstractApplicationContext#refresh //刷新创建容器
->AbstractApplicationContext#registerBeanPostProcessors //注册bean的后置处理器
->PostProcessorRegistrationDelegate#registerBeanPostProcessors()PriorityOrdered->Ordered->others // 按照优先级注册Bean
//我们知道AnnotationAwareAspectJAutoProxyCreator是实现了Order接口的,因此我们调试一次看在什么时候注册
->在代码beanFactory.getBean(ppName, BeanPostProcessor.class)处,回去创建Bean,后面创建Bean的流程和普通bean几乎是一样的-
->AbstractBeanFactory#getBean() //Bean工厂获取bean
->AbstractBeanFactory#doGetBean //Bean工厂获取Bean
->AbstractAutowireCapableBeanFactory#createBean() //创建Bean实例
->AbstractAutowireCapableBeanFactory#doCreateBean //创建Bean实例
->AbstractAutowireCapableBeanFactory#populateBean //Bean属性赋值
->AbstractAutowireCapableBeanFactory#initializeBean() //Bean初始化 (invokeAwareMethods,applyBeanPostProcessorsBeforeInitialization,invokeInitMethods,applyBeanPostProcessorsAfterInitialization)
->创建Bean成功
在PostProcessorRegistrationDelegate中beanFactory.addBeanPostProcessor添加到BeanFactory
- 具体的流程可以参考:08-spring Bean生命周期详细图解
2.3 代理过程
- 熟悉Aop的原理我们知道Aop是基于代理来实现的,按照11-springAop使用的例子,我们往容器中注册了一个Calculator类型的Bean,这个Bean的方法被调用时,前后被拦截,底层原理实际上是容器中的bean不再是最原始的Calculator类型Bean,而是一个被代理了的Bean,我们来看看这个代理的过程在哪里完成。这个流程还是基于08-spring Bean生命周期详细图解
AbstractApplicationContext#refresh //刷新创建容器
->AbstractApplicationContext#finishBeanFactoryInitialization //实例化懒加载Bean,通常业务Bean就在这一步实例化
->AbstractApplicationContext#finishBeanFactoryInitialization //实例化单例Bean
->ConfigurableListableBeanFactory#preInstantiateSingletons //实例化剩余的费非懒加载Bean
->DefaultListableBeanFactory#preInstantiateSingletons // 实例化单例Bean
->AbstractBeanFactory#getBean() //Bean工厂获取Bean -- 这一步开始和前面的BeanPostProcessor流程一样了
->AbstractBeanFactory#doGetBean //Bean工厂获取Bean
->AbstractAutowireCapableBeanFactory#createBean()//创建Bean实例,在createBean()方法里面注意了,这后面的流程会不一样
->AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation //调用before-instantiation post-processors,这里并不会创建bean成功
->AbstractAutowireCapableBeanFactory#doCreateBean //创建Bean实例
->AbstractAutowireCapableBeanFactory#populateBean //Bean属性赋值
->AbstractAutowireCapableBeanFactory#initializeBean() //Bean初始化
->AbstractAutowireCapableBeanFactory#invokeAwareMethods //Aware方法调用
->AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization //BeanPosProcessor前置处理(但是这里面没有改变被代理的bean),
->AbstractAutowireCapableBeanFactory#invokeInitMethods //初始化方法调用(init-method,InitializingBean接口afterPropertiesSet方法)
->AbstractAutoProxyCreator#postProcessAfterInitialization //BeanPosProcessor后置处理(这里面返回了被代理的bean对象)
->AbstractAutoProxyCreator#wrapIfNecessary //尝试返回bean
->AbstractAutoProxyCreator#createProxy // 尝试创建bean代理对象
->在createProxy里面创建bean的代理对象成功
三、小结
- 本文是12-springAop 源码初探,暂时给出Aop的实现引入,首先是通过注解@EnableAspectJAutoProxy往容器注入了一个AnnotationAwareAspectJAutoProxyCreator类型的Bean
,它的BeanId是"org.springframework.aop.config.internalAutoProxyCreator",这个Bean继承了BeanPostProcessor的很多子接口还要其他接口,具备比较强的Bena后置处理能力,在Bean的初始化过程中对Bean的切面增强起到非常关键的作用,由于篇幅和难度的因素,前面只给出了该Bean的注册流程和增强流程的方法调用链,在下一篇文章中给出更为详细的分析。
四、AOP中的术语
- 通知(Advice):需要完成的事情和时机的集合。比如@Before定义了在目标方法之前需要做的事情,一共有5种通知类型,定义了“何时”和“做什么”,比如:下面代码就是说明了在方法执行之前,调用对应的逻辑,体现了:要完成的事情和时机
@Before("pointCut()")
public void logBefore() {
System.out.println("log @Before...");
}
-
连接点(joinpoint):能够插入切面的点,简单来说就是能够被我们增强的点。因为并非所有的时机都能被增强,比较典型的有方法调用前后,抛出异常时,我们总是在这些连接点里面去找到我们感兴趣的点来做增强,在Spring中连接点都是方法。在Java代码中连接点是一个接口,实现类不多,比如ReflectiveMethodInvocation是一个,AOP中调用增强方法就是使用该类实例来实现的。
-
切点(pointcut):切点就是连接点里面的一个子集,切点用来描述连接点,复合描述的就做增强,反之就不做增强。比如我对方法调用前和抛出异常感兴趣,这两个连接点就是我关注的切点,它定义了“何处”。如下就是一个切点描述
@Pointcut("execution(public int com.intellif.ch10.MyTarget.*(..))")
- 切面(Aspect):切点+通知=切面。切面就包含了:在哪里、做什么、什么时候做这三个关键要素。@Aspect就可以理解为切面
- 织入:将切面应用到目标对象来达到AOP拦截增强的目的。切面在指定的连接点被织入到目标对象中,在目标对象的生命周期中有多个点可以织入,在AOP中,返回代理对象就是一个织入的过程。
编译期: 切面在目标类编译时期被织入,这种方式需要特殊编译器。AspectJ的织入编译器就是以这种方式织入切面。
类加载期:切面在类加载到JVM ,这种方式需要特殊的类加载器,他可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5 的 LTW 就支持这种织入方式
运行期: 切面在应用运行期间的某个时刻被织入。一般情况下,在织入切面时候,AOP 容器会为目标对象动态的创建代理对象。Spring AOP 就是以这种方式织入切面。