12-springAop 源码初探

文章目录

  • Aop 源码分析
    • 一、主要类
      • 1.1 @EnableAspectJAutoProxy
      • 1.2 AspectJAutoProxyRegistrar
        • 1.2.1 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary
    • 二、AnnotationAwareAspectJAutoProxyCreator
      • 2.1 继承关系
      • 2.2 注册流程
      • 2.3 代理过程
    • 三、小结
    • 四、AOP中的术语
    • 五、参考

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 就是以这种方式织入切面。

五、参考

  • [1] Spring的IOC容器系列的设计与实现:BeanFactory和ApplicationContext

你可能感兴趣的:(Spring)