转载

AOP源码解析

<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-aspects</artifactId>
     <version>5.1.5.RELEASE</version>
   </dependency>

通知

@Before
@After
@AfterReturning
@AfterThrowing
@Around

连接点

  • 业务层的所有方法,叫做连接点
  • 业务类中可以被增强的方法都叫做连接点

切点

  • 能切入切面逻辑的方法,叫做切点
  • 实际被增强的方法叫做切入点 ,其他的那些没有被增强的方法(连接点)不是切点

切面

  • 定义了增强方法的类就叫做切面

实现

  • 在配置类上开启切面,使用 @EnableAspectJAutoProxy
@Configuration
@ComponentScan(value = {"cn.tedu.demo"})
@EnableAsync
@EnableAspectJAutoProxy
public class FirstConfig{}
  • 使用五个不同的通知完成切入:
/**
 * 切面,使用@Aspect标注
 */
@Component
@Aspect
public class CustomAspect{

    /**
     * 使用@PointCut定义切入点
     */
    @Pointcut(value = "execution(* cn.tedu.demo.aspect.AspectInvok.invok(..))")
    public void pointCut(){}

    /**
     * 前置通知,在指定方法之前执行
     * @param point JoinPoint对象,可以获取切点的各种属性,比如入参的参数等
     */
    @Before(value = "pointCut()")
    public void before(JoinPoint point){
        //获取入参的参数的值
        Object[] args = point.getArgs();
        System.out.println(Arrays.asList(args));
        //获取MethodSignature,其中可以获取切点的各种属性,比如方法返回类型,参数等等
        MethodSignature signature = (MethodSignature) point.getSignature();
        String[] parameterNames = signature.getParameterNames();
        System.out.println(Arrays.asList(parameterNames));
        System.out.println("在方法之前执行");
    }

    /**
     * 在切点之后执行
     * @param point JoinPoint对象
     */
    @After(value = "pointCut()",argNames = "point")
    public void after(JoinPoint point){
        System.out.println("在方法之后执行");
    }

    /**
     * 在方法前后都会执行
     * @param point
     */
    @Around(value = "pointCut()")
    public void around(ProceedingJoinPoint point)throws Throwable {
        System.out.println("前置执行");
        //执行方法,可以获取返回值,否则方法将不会执行
        Object result = point.proceed(point.getArgs());
        System.out.println("后置执行,执行的结果=="+result);
    }

    /**
     * 正常返回通知,
     * @param point Joinpoint对象
     * @param result 方法执行返回的结果,需要和@AfterReturning注解中returning中的属性值相同,否则不能自动装配
     */
    @AfterReturning(value = "pointCut()",returning = "result")
    public void afterReturning(JoinPoint point,Object result){
        System.out.println("正常返回执行,执行的结果为:"+result);
    }

    /**
     * 异常返回执行,程序出现异常了才会执行
     * @param point
     * @param ex 切入点执行抛出的异常,需要和@AfterThrowing注解的throwing值相同,否则不能完成自动装配
     */
    @AfterThrowing(value = "pointCut()",throwing = "ex")
    public void afterThrowing(JoinPoint point,Exception ex){
        System.out.println("异常返回执行,执行的异常为:"+ex);
    }
}

注解的实现

  • 详细请看我的上一篇博客
  • 定义一个注解,如下:

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MyAnnotation {
        Stringname()default "陈加兵";
        int age()default 22;
    }
    
  • 定义一个切面,使用注解如下:

    @Component
    @Aspect
    public class CustomAspect{
    
        /**
         * 使用@PointCut定义切入点
         */
        @Pointcut(value = "@annotation(cn.tedu.demo.aspect.MyAnnotation)")
        public void pointCut(){}
    
        /**
         * 前置通知,在指定方法之前执行
         * @param point JoinPoint对象,可以获取切点的各种属性,比如入参的参数等
         */
        @Before(value = "pointCut()")
        public void before(JoinPoint point){
            //获取MethodSignature,其中可以获取切点的各种属性,比如方法返回类型,参数等等
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            //获取方法上指定的注解
            MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
            System.out.println("name="+myAnnotation.name());
            System.out.println("在方法之前执行");
        }
    }
    

源码解析

@EnableAspectJAutoProxy

  • @EnableAspectJAutoProxy 该注解中可以看出使用了 @Import(AspectJAutoProxyRegistrar.class) ,因此实际作用的类就是 AspectJAutoProxyRegistrar ,因此我们必须跟进源码去看。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

AspectJAutoProxyRegistrar

ImportBeanDefinitionRegistrar
AnnotationAutoProxyCreator
class AspectJAutoProxyRegistrarimplements ImportBeanDefinitionRegistrar{

	/**
	* 向容器中注入AnnotationAutoProxyCreator
	*/
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//调用方法注册AnnotationAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        //获取@EnableAspectJAutoProxy注解中两个属性的值
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        //判断注解属性的值
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}

AnnotationAutoProxyCreator【创建代理】

概念

Map<Object, Boolean>

分析

  • @EnableAspectJAutoProxy 注解的主要作用就是向容器中注入 AnnotationAutoProxyCreator ,ID为 org.springframework.aop.config.internalAutoProxyCreator ,因此切面的关键类就是这个,我们看看继承关系图,如下:

AOP源码解析

  • 从继承关系中可以看到该类及其父类实现了两个重要的接口,如下:
    InstantiationAwareBeanPostProcessor
    BeanFactoryAware
    
  • 通过上面的分析可以知道,AOP的主要功能必定是在 AnnotationAutoProxyCreator 这个Bean的初始化和实例化前后执行逻辑,无非就是上面两个接口定义的方法,我们可以在对应的方法中打断点跟踪代码。

代码跟踪

  • 刷新容器种执行 registerBeanPostProcessors(beanFactory) 方法将全部的后置处理器注入到容器中,在其中执行执行后续的setBeanFactory的方法

    • 根据Bean的生命周期我们可以判断最新执行的一定是实现Aware方法的setBeanFactory方法【在invokeAwareMethods()方法中执行】,实际执行也是符合我们的猜想,第一个执行的方法就是 org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#setBeanFactory
      • 创建 AspectJAdvisorFactory :顾名思义,当然是从标注 @Aspect的类中 创建增强器【切面增强的方法】
      • 创建 BeanFactoryAspectJAdvisorsBuilder :简单的说就是创建增强器的辅助类,用来构造增强器
    @Override
    	public void setBeanFactory(BeanFactory beanFactory){
            //调用父类的方法
    		super.setBeanFactory(beanFactory);
    		if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
    			throw new IllegalArgumentException(
    					"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
    		}
            //实际执行的是initBeanFactory
    		initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
    	}
    
    /*******************************initBeanFactory**************************/
    	@Override
    	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory){
    		super.initBeanFactory(beanFactory);
            //创建切面增强器工厂
    		if (this.aspectJAdvisorFactory == null) {
    			this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
    		}
            //创建切面增强生成器
    		this.aspectJAdvisorsBuilder =
    				new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
    	}
    
  • 刷新容器方法中执行 finishBeanFactoryInitialization(beanFactory) 【实例化剩余的单例Bean】

    • getBean()—>doGetBean—>createBean,在createBean方法中执行 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); 【在实例化之前给一个机会返回一个代理】

      • 内部执行 bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);

        • 内部循环遍历后置处理器,判断类型为 InstantiationAwareBeanPostProcessor ,执行 postProcessBeforeInstantiation() 方法【在实例化之前调用,接口定义】。

          • 此时执行到 AbstractAutoProxyCreator#postProcessBeforeInstantiation ,源码如下:

            • 这个方法的主要作用就是查找切面类和已经有了TargetSource的类,这些类都是不需要增强的,设置adviseBean的value为false,后续就不需要创建代理对象了
              /**
              * 在实例化之前执行逻辑,如果返回不为null,后续的属性赋值等操作将不会执行
              *  主要的作用
              */
              public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName){
                      //获取cacheKey,主要是和FactoryBean对象区别
              		Object cacheKey = getCacheKey(beanClass, beanName);
              		//beanName为空,或者targetSourcedBeans不包含当前Bean
                 		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
                       //如果需要增强的Bean已经包含了当前Bean,后续流程不需要执行,返回null即可
              			if (this.advisedBeans.containsKey(cacheKey)) {
              				return null;
              			}
                 /**isInfrastructureClass(beanClass):【如果当前Bean是基础的类【实现了Advice、Pointcut、Advisor、AopInfrastructureBean】并且满足this.aspectJAdvisorFactory不为null&&当前类被@Aspect注解标注了】
                          *shouldSkip(beanClass, beanName):
                          *       ①获取所有的候选的增强器【List<Advisor> candidateAdvisors = findCandidateAdvisors();】
                          *       ②循环候选增强器,判断类型是否是AspectJPointcutAdvisor
                          */
              			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                     //如果满足条件,那么表示该类是一个切面,不是需要增强的Bean,设置value为false
              				this.advisedBeans.put(cacheKey, Boolean.FALSE);
              				return null;
              			}
              		}
              
              		//获取自定义的TargetSource
              		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
                      //如果存在,那么可以直接创建代理对象
              		if (targetSource != null) {
              			if (StringUtils.hasLength(beanName)) {
              				this.targetSourcedBeans.add(beanName);
              			}
              			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
              			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
              			this.proxyTypes.put(cacheKey, proxy.getClass());
              			return proxy;
              		}
              
              		return null;
              	}
              
          • 代码继续执行,发现 postProcessPropertiespostProcessBeforeInitializationpostProcessBeforeInitialization 都是默认的实现,这里跳过。

          • 真正创建代理对象的是在 postProcessAfterInitialization 中,逻辑如下:
            • ①判断bean是否为null和earlyProxyReferences中是否存在当前的Bean
            • ②如果满足条件,调用 wrapIfNecessary(bean, beanName, cacheKey) 方法,封装Bean,其实就是创建代理对象
            • ③进入 wrapIfNecessary 方法
              • ①做一些判断,包括是否是targetSourcedBeans是否包含,是否是基础类,是否应该跳过,是否adviseBean中的value为false【不需要增强的Bean】,满足以上条件的都直接返回bean,不需要创建代理
              • ②调用方法获取能够作用于当前Bean的增强器(通知方法集合)封装在 specificInterceptors ,代码跟进,最重要的实现是在 org.springframework.aop.support.AopUtils.canApply(org.springframework.aop.Advisor, java.lang.Class<?>, boolean) 这个方法中,大致的思想就是
              • ③判断specificInterceptors是否为null,如果为空,表示当前Bean不需要增强,设置adviseBean的值为false,反之需要增强,此时就需要创建代理了,此时主要调用的是 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))
            • ④ 进入 createProxy 方法
              • ① 创建ProxyFactory,主要作用就是创建代理的工厂,其中封装了Advisor,targetSource,getProxy()【创建代理】方法等
              • ② 判断是否应该直接代理目标类【if (!proxyFactory.isProxyTargetClass())】
              • ③ 调用 evaluateProxyInterfaces(beanClass, proxyFactory); 方法,主要的作用就是检查当前Bean实现的接口是否符合要求能够创建代理对象【不能是 InitializingBeanDisposableBean , Closeable , AutoCloseable 等接口】,如果满足直接设置到ProxyFactory中,否则设置 proxyTargetClass=true 【直接代理目标类targetSource】
              • ④ 调用 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors) 方法,将公共的拦截器和适配的拦截器 specificInterceptors 一起返回
                • ① 根据指定的 this.interceptorNames 拦截器名称从容器中获取Bean,将其解析成 commonInterceptors
                • ② 遍历commonInterceptors和specificInterceptors将其封装成Advisor数组返回
              • ⑤ 将advisor和targetSource添加到ProxyFactory中
              • ⑥ 调用 proxyFactory.getProxy(getProxyClassLoader()) 方法,获取代理对象
                • ① 最终调用的是 org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy 的方法创建代理对象,是AopProxyFactory默认实现类中的方法,具体逻辑如下:
                  • 如果targetClass是接口或者继承Proxy使用JDK的动态代理,否则使用Cglib代理
            • ⑤ 将创建的代理对象proxy存放在 proxyTypes 中,返回proxy
            • ⑥ 至此代理对象创建完成

代理执行

  • 上面解释了代理对象的创建流程,下面就开始真正的执行和增强的流程了,需要了解到五种通知类型在什么时候执行,执行的顺序是什么?
  • 未完待续。。。。。
原文  https://chenjiabing666.github.io/2019/07/07/AOP源码解析/
正文到此结束
Loading...