Spring 5.x 源码之旅-45Aspect注解解析二

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

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

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通知是什么

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


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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值