2023-09-16  阅读(43)
原文作者:王伟王胖胖 原文地址: https://blog.csdn.net/wangwei19871103/article/details/105209011

ReflectiveAspectJAdvisorFactory的getAdvisor

继续上一篇,我们现在已经获取到了切面对象里的方法,现在就是解析这些方法的注解来进行创建Advisor通知器,内部会创建Advice通知,怎么连切点都没分析就创建通知器了?其实切点就在这里面解析啦。

    @Override
    	@Nullable
    	public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
    			int declarationOrderInAspect, String aspectName) {
    
    		validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    		//获取切点表达式
    		AspectJExpressionPointcut expressionPointcut = getPointcut(
    				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    		if (expressionPointcut == null) {
    			return null;
    		}
    
    		return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
    				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    	}

getPointcut获取切点表达式

首先当然去获取切点啦,先找下方法注解里面有没有AspectJ相关的注解Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class,没有当然就不用处理啦。有的话就要创建切点表达式,然后返回。

    @Nullable
    	private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
    		AspectJAnnotation<?> aspectJAnnotation =//找AspectJAnnotation注解
    				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    		if (aspectJAnnotation == null) {
    			return null;
    		}
    
    		AspectJExpressionPointcut ajexp =
    				new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
    		ajexp.setExpression(aspectJAnnotation.getPointcutExpression());//设置表达式
    		if (this.beanFactory != null) {
    			ajexp.setBeanFactory(this.beanFactory);
    		}
    		return ajexp;
    	}

AbstractAspectJAdvisorFactory的findAspectJAnnotationOnMethod

遍历所有的AspectJ注解类型,寻找是否有该类的注解,有的话就封装成AspectJAnnotation返回。

    private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
    			Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
    
    
    
    	@Nullable
    	protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
    		for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {//遍历所有注解,找到就返回
    			AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
    			if (foundAnnotation != null) {
    				return foundAnnotation;
    			}
    		}
    		return null;
    	}

InstantiationModelAwarePointcutAdvisorImpl构造方法

构造函数中最后的地方会实例化Advice

202309162317470021.png

InstantiationModelAwarePointcutAdvisorImpl的instantiateAdvice

这里才是真的创建Advice通知。

    	private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
    		Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
    				this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    		return (advice != null ? advice : EMPTY_ADVICE);
    	}

ReflectiveAspectJAdvisorFactory的getAdvice获取通知

这个是最终的获取通知的方法,首先进行了一些验证,然后获得AspectJ的注解,根据注解类型进行创建,最后设置一些参数:

    @Override
    	@Nullable
    	public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
    			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    
    		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    		validate(candidateAspectClass);
    
    		AspectJAnnotation<?> aspectJAnnotation =
    				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    		if (aspectJAnnotation == null) {
    			return null;
    		}
    
    		if (!isAspect(candidateAspectClass)) {
    			throw new AopConfigException("Advice must be declared inside an aspect type: " +
    					"Offending method '" + candidateAdviceMethod + "' in class [" +
    					candidateAspectClass.getName() + "]");
    		}
    
    		if (logger.isDebugEnabled()) {
    			logger.debug("Found AspectJ method: " + candidateAdviceMethod);
    		}
    
    		AbstractAspectJAdvice springAdvice;
    		//通知类型
    		switch (aspectJAnnotation.getAnnotationType()) {
    			case AtPointcut:
    				if (logger.isDebugEnabled()) {
    					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
    				}
    				return null;
    			case AtAround:
    				springAdvice = new AspectJAroundAdvice(
    						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    				break;
    			case AtBefore:
    				springAdvice = new AspectJMethodBeforeAdvice(
    						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    				break;
    			case AtAfter:
    				springAdvice = new AspectJAfterAdvice(
    						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    				break;
    			case AtAfterReturning:
    				springAdvice = new AspectJAfterReturningAdvice(
    						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    				AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
    				if (StringUtils.hasText(afterReturningAnnotation.returning())) {
    					springAdvice.setReturningName(afterReturningAnnotation.returning());
    				}
    				break;
    			case AtAfterThrowing:
    				springAdvice = new AspectJAfterThrowingAdvice(
    						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
    				AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
    				if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
    					springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
    				}
    				break;
    			default:
    				throw new UnsupportedOperationException(
    						"Unsupported advice type on method: " + candidateAdviceMethod);
    		}
    
    		// Now to configure the advice...
    		springAdvice.setAspectName(aspectName);//切点名
    		springAdvice.setDeclarationOrder(declarationOrder);
    		String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    		if (argNames != null) {
    			springAdvice.setArgumentNamesFromStringArray(argNames);
    		}
    		springAdvice.calculateArgumentBindings();
    
    		return springAdvice;
    	}

Advice通知是什么

其实他只是一个标记接口:

202309162317474342.png
我们的AOP最终都是这5类做的增强:

202309162317478423.png

基本的切面解析和通知创建知道怎么来的,后面就看怎么把通知用上去了,是在初始化后的处理器AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInitialization方法里,下次讲吧。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文