• SpringAOP源码解析之advice构建排序(二)


    上一章我们知道Spring开启AOP之后会注册AnnotationAwareAspectJAutoProxyCreator类的定义信息,所以在属性注入之后initializeBean的applyBeanPostProcessorsAfterInitialization方法执行的时候调用AnnotationAwareAspectJAutoProxyCreator父类(AbstractAutoProxyCreator)的postProcessAfterInitialization方法来创建AOP的代理。

    // AbstractAutoProxyCreator类
    @Override
    	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    		if (bean != null) {
    			Object cacheKey = getCacheKey(bean.getClass(), beanName);
    			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
    				// 真正进行处理的地方,里面有代码很明显是用来创建代理对象的
    				return wrapIfNecessary(bean, beanName, cacheKey);
    			}
    		}
    		return bean;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    然后我们创建一个Aspect,方便我们这章的分析

    @Component
    @Aspect
    public class ThamNotVeryUsefulAspect {
    	@Pointcut("execution(* com.qhyu.cloud.aop.service.QhyuAspectService.*(..))") // the pointcut expression
    	private void thamAnyOldTransfer() {} // the pointcut signature
    
    	@Before("thamAnyOldTransfer()")
    	public void before(){
    		System.out.println("tham Before 方法调用前");
    	}
    
    	@After("thamAnyOldTransfer()")
    	public void after(){
    		System.out.println("tham After 方法调用前");
    	}
    	
    	@AfterReturning("thamAnyOldTransfer()")
    	public void afterReturning(){
    		System.out.println("tham afterReturning");
    	}
    	
    	@AfterThrowing("thamAnyOldTransfer()")
    	public void afterThrowing(){
    		System.out.println("tham AfterThrowing");
    	}
    	
    	@Around("thamAnyOldTransfer()")
    	public Object  around(ProceedingJoinPoint pjp) throws Throwable{
    		// start stopwatch
    		System.out.println("tham around before");
    		Object retVal = pjp.proceed();
    		// stop stopwatch
    		System.out.println("tham around after");
    		return retVal;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    放一张整体的流程图,方便我们查看知通构建的整体流程。

    在这里插入图片描述

    wrapIfNecessary方法的实现流程

    1、首先判断bean是否需要被代理,如果不需要,直接返回原始bean实例 。

    2、如果需要代理,则获取bean所有的advisor,并根据advisor的pointcout对bean进行匹配,得到所有需要拦截的方法 。

    3、根据bean的类型和配置信息,决定使用哪种类型的代理对象,CGLIB或者JDK动态代理 。

    4、将advisor和代理对象绑定,并将代理对象返回。

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    		// targetSource是干嘛得
    		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    			return bean;
    		}
    		// advisedBeans不会进行代理
    		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    			return bean;
    		}
    		// 什么情况会shouldSkip,提前解析切面
    		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    			this.advisedBeans.put(cacheKey, Boolean.FALSE);
    			return bean;
    		}
    
    		// Create proxy if we have advice.
    		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    		if (specificInterceptors != DO_NOT_PROXY) {
    			this.advisedBeans.put(cacheKey, Boolean.TRUE);
    			// 创建代理对象
    			Object proxy = createProxy(
    					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    			this.proxyTypes.put(cacheKey, proxy.getClass());
    			return proxy;
    		}
    
    		this.advisedBeans.put(cacheKey, Boolean.FALSE);
    		return bean;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    findCandidateAdvisors获取候选的Advisors

    获取候选的Advisors是使用的子类(AnnotationAwareAspectJAutoProxuCreator)的实现,然后我们的基于注解的Aspect(ThamNotVeryUsefulAspect)会执行this.aspectJAdvisorsBuilder.buildAspectJAdvisors()来添加

    @Override
    	protected List<Advisor> findCandidateAdvisors() {
    		// Add all the Spring advisors found according to superclass rules.
    		List<Advisor> advisors = super.findCandidateAdvisors();
    		// Build Advisors for all AspectJ aspects in the bean factory.
    		if (this.aspectJAdvisorsBuilder != null) {
    			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    		}
    		return advisors;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    构建AspectJ的Advisors

    首先在BeanFactoryAspectJAdvisorsBuilder的this.advisorFactory.getAdvisors(factory)打个断点

    在这里插入图片描述

    然后我断点进来之后我就发现了这个其实是有顺序的,也就是说明在这个内部实现了第一次排序。

    在这里插入图片描述

    第一次排序

    接下来会进入ReflectiveAspectJAdvisorFactory的getAdvisors方法。其中核心就是for循环中的getAdvisorMethods方法。

    public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    		Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    		String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    		validate(aspectClass);
    
    		// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    		// so that it will only instantiate once.
    		MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
    				new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
    
    		List<Advisor> advisors = new ArrayList<>();
    		//遍历切面方法,这里会把标注了@Pointcut 注解的排除掉,只剩下通知注解,如@Before,@After
    		for (Method method : getAdvisorMethods(aspectClass)) {
    			Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
    			if (advisor != null) {
    				advisors.add(advisor);
    			}
    		}
    
    		// If it's a per target aspect, emit the dummy instantiating aspect.
    		if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
    			Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
    			advisors.add(0, instantiationAdvisor);
    		}
    
    		// Find introduction fields.
    		for (Field field : aspectClass.getDeclaredFields()) {
    			Advisor advisor = getDeclareParentsAdvisor(field);
    			if (advisor != null) {
    				advisors.add(advisor);
    			}
    		}
    
    		return advisors;
    	}
    	// 遍历切面方法时进行排序,可以理解为第一次排序
    	private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    		List<Method> methods = new ArrayList<>();
    		ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
    		if (methods.size() > 1) {
    			methods.sort(adviceMethodComparator);
    		}
    		return methods;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    首先会排除@PointCut的方法

    private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
    			.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));
    
    • 1
    • 2

    然后创建了一个比较器

    private static final Comparator<Method> adviceMethodComparator;
    
    	static {
    		// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
    		// an @After advice method will actually be invoked after @AfterReturning and
    		// @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
    		// invokes proceed() in a `try` block and only invokes the @After advice method
    		// in a corresponding `finally` block.
    		Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
    				new InstanceComparator<>(
    						Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
    				(Converter<Method, Annotation>) method -> {
    					AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
    					return (ann != null ? ann.getAnnotation() : null);
    				});
    		Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
    		adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    很明显是按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class的顺序进行顺序的构建。

    第二次排序

    根据AbstractAdvisorAutoProxyCreator的findEligibleAdvisors的代码可知,第一次排序发生在findCandidateAdvisors方法。第二次排序则发生在次方法中的sortAdvisors。

    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    	
    		List<Advisor> candidateAdvisors = findCandidateAdvisors();
    		// Around before after afterReturing afterThrowing
    		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    		extendAdvisors(eligibleAdvisors);
    		if (!eligibleAdvisors.isEmpty()) {
    			// 这里是通过order进行排序的
    			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    		}
    		return eligibleAdvisors;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    第一次排序是对一个Aspect中的所有advice进行排序,第二次排序是对Aspect进行排序,可以通过实现Order接口或者@Order注解来设置顺序,如果没有实现order的话,是以加载的顺序来的。一般情况下加载的顺序可能不可控,所以如果有必要的话需要实现order。

    创建两个Aspect,然后都没有实现@Order

    在这里插入图片描述

    顺序是ThamNotVersyUsefulAspect在NotVeryUsefulAspect之前

    在这里插入图片描述

    但是如果我们把两个放一起,这个时候NotVeryUsefulAspect先加载就会在前面。

    在这里插入图片描述

    在这里插入图片描述

    如果我们设置ThamNotVeryUsefulAspect的Order(98),NotVeryUsefulAspect的Order(99),Order小的将排在前面。

    @Component
    @Aspect
    @Order(99)
    public class NotVeryUsefulAspect {
    }
    
    @Component
    @Aspect
    @Order(98)
    public class ThamNotVeryUsefulAspect {
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    写在最后

    本章主要描述构建通知的顺序,正在的执行过程将在下一章节进行分析。

  • 相关阅读:
    layui手机端使用laydate时间选择器被输入法遮挡的解决方案
    docker命令介绍,镜像制作,容器启动,进入容器操作等
    影响多用户商城系统价格的因素有哪些?
    (一)shell编程
    SpringCloud微服务技术栈-什么是Docker?怎么安装Docker?
    测试理论与方法----测试流程第三个环节:设计测试用例
    你不知道的vue3:使用runWithContext实现在非 setup 期间使用inject
    开源移动核心网Magma架构设计启示
    使用cython加速代码运行
    node exec(“clip“) 复制到剪切板 乱码
  • 原文地址:https://blog.csdn.net/Tanganling/article/details/134026560