7.Spring 源码解析之AOP获取增强器过程

7.1 Spring 注解之 @EnableAspectJAutoProxy

Spring 开启自动代理是通过 @EnableAspectJAutoProxy 来实现的,看看这个注解都有哪些功能,代码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
	boolean proxyTargetClass() default false;
	boolean exposeProxy() default false;
}

发现引入了AspectJAutoProxyRegistrar.class 组件,内部主要实现了注册 AnnotationAwareAspectJAutoProxyCreator.class 组件,代码如下:

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)
	|- registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
		|- registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
			|- public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";

AnnotationAwareAspectJAutoProxyCreator.class 这个类的组织关系,如下图所示:

在这里插入图片描述

发现这个类是一个BeanPostProcessor,该类在bean生命周期中,分析过 ,这里不再赘述。在生命周期中的函数主要有以下几个。

在这里插入图片描述

7.2 Spring 获取增强器过程

在bean实例化过程中,先调用 postProcessBeforeInstantiation() ,经过源码分析,该函数主要做了切面解析过程,主要逻辑如下:

// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

从注释中我们可以看到,该方法主要作用是:给一个机会返回一个目标bean实例的代理对象。

if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return null;
}

主要有两步骤,先检查是否含有增强相关的注解,如下:

protected boolean isInfrastructureClass(Class<?> beanClass) {
    boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
        Pointcut.class.isAssignableFrom(beanClass) ||
        Advisor.class.isAssignableFrom(beanClass) ||
        AopInfrastructureBean.class.isAssignableFrom(beanClass);
    return retVal;
}

protected boolean isInfrastructureClass(Class<?> beanClass) {
	return (super.isInfrastructureClass(beanClass) ||
				(this.aspectJAdvisorFactory != null && 
                 this.aspectJAdvisorFactory.isAspect(beanClass)));
}

判断当前类是否是切面类,如果是,直接返回,因为切面类肯定不需要增强,不是时,会调用shouldSkip ,调用过程如下:

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;
}

这里面主要查找两种增强,Spring advisor(事务等用的) 和 AspectJ aspects(@Aspect用的)

7.2.1 获取 Spring Advisor

Spring 原生的 Advisor 是通过检索工具类来实现的,BeanFactoryAdvisorRetrievalHelper

advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);

查找所有Advisor家族的类,AnnotationAwareAspectJAutoProxyCreator 没有实现过Advisor,这部分等到后面事务在解析。

7.2.2 获取 AspectJ Advisor

buildAspectJAdvisors 利用了缓存,在AnnotationAwareAspectJAutoProxyCreator 中存放了 aspectBeanNames 所有的切面beanName。具体是通过查找所有的组件,然后一个个匹配的思想,解析一遍比较耗时,要给缓存起来。

String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);

然后循环这些beanName,把这些beanName 转换成beanType,然后判断这些beanType是不是切面类。

private boolean hasAspectAnnotation(Class<?> clazz) {
	return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}

然后获取切面类所有方法,排除掉@Pointcut方法,这个是获取切点表达式使用的。

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;
}

// Exclude @Pointcut methods
private static final MethodFilter adviceMethodFilter = 
		ReflectionUtils.USER_DECLARED_METHODS.and(
			method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));
  • 获取切点表达式

    AspectJExpressionPointcut expressionPointcut = getPointcut(
    				candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    
  • 组装Advisor类

    new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
    				this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    
  • 获取方法上的注解

    AspectJAnnotation<?> aspectJAnnotation =
    				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    
  • 创建通知

    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())) {![aop-2](D:\code\idea\atom\spring\image\新建文件夹\aop-2.png)
    			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);
    }
    

每个方法都遍历完后,获取到的Advisors 和beanName 促成一个map,存放到缓存中,Map<String, List> advisorsCache,如下图所示:
在这里插入图片描述

7.3 获取增强器过程图解

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值