您现在的位置是:首页 >技术交流 >Spring AOP源码分析篇二:AnnotationAwareAspectJAutoProxyCreator解析并获取advisor、切点pointcut网站首页技术交流
Spring AOP源码分析篇二:AnnotationAwareAspectJAutoProxyCreator解析并获取advisor、切点pointcut
目录
2.1. AnnotationAwareAspectJAutoProxyCreator
2.1.1. findCandidateAdvisors()
2.2. AbstractAdvisorAutoProxyCreator
1. 前言
在上篇文章中,Spring AOP源码分析篇一:@EnableAspectJAutoProxy的来龙去脉讲述了AOP的开端,其实就是注册了AnnotationAwareAspectJAutoProxyCreator的beanDefinition到容器中,并且在文章结尾处还给出了这个类的继承关系,这个类和他的父类们极为重要,负责把切面类bean的通知(advice)找出来,并用这些通知们生成代理,本文主要围绕他们去开展。
老规矩,先祭出流程图
看不清没关系,奉上高清链接
aop创建动态代理流程| ProcessOn免费在线作图,在线流程图,在线思维导图
Spring AOP流程
- 在getBean()生命周期初始化后,执行后置处理器AbstractAutoProxyCreator#postProcessAfterInitialization()方法,找到所有的切面 bean(被@Aspect注解的bean),并遍历每个切面的所有方法,根据 @Before, @After 等advice注解生成对应的 Advisor(排除@Pointcut注解的方法)。
- 遍历 Advisor 数组,找到和当前bean匹配的advisors。
- 如果能符合当前bean匹配的advisors,就把这些过滤好的advisors用作生成aop对象(AOP生成对象有jdk和cglib两种方式)
而上面三步可以用下面的图来讲解,这样就能很清晰的看到AnnotationAwareAspectJAutoProxyCreator以及父类在aop流程的作用了
这样看觉得还不够细的话,下面给个更细的图
紫色部分(AnnotationaWareAspectJAutoProxyCreator):获取所有的advisors
粉色部分(AbstractAdvisorAutoProxyCreator):根据当前bean过滤并匹配紫色部分拿到的advisors
青色部分(AbstractAutoProxyCreator):将过滤好的advisors拿来创建aop对象
所以本文打算用逆序的方法讲起,就是先讲紫色部分,再讲粉色部分,最后再讲青色部分
2. 源码分析
2.1. AnnotationAwareAspectJAutoProxyCreator
从上面图中可知,流程的入手点是AnnotationAwareAspectJAutoProxyCreator类的findCandidateAdvisors()方法,这个方法有两步操作
1.执行父类AbstractAutoProxy#findCandidateAdvisors()方法,主要是获取配置在xml中的Advisor(纯POJO切面)和原生接口的AOP的Advisor。
2.调用buildAspectJAdvisors()方法,这个方法才是我们本次重点流程,因为一般我们使用的都是@Aspect、@Before、@After等注解,就是在这里解析的并获取所有advisor。
我们看一下findCandidateAdvisors()方法的源码
protected List<Advisor> findCandidateAdvisors() {
// 找出xml配置的Advisor和原生接口的AOP的Advisor 找出事务相关的advisor
// 先找到所有Advisor类型的Bean对象
List<Advisor> advisors = super.findCandidateAdvisors();
// 再从所有Aspect切面中解析得到Advisor对象
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
//返回我们所有的通知
return advisors;
2.1.1. findCandidateAdvisors()
在讲源码前,我们先看看两个demo,如下所示
1、纯POJO切面
public class MyAspectV2 {
//前置增强
public void asBefore(){
System.out.println("这是前置增强");
}
//后置增强
public void asAfterReturning(){
System.out.println("这是后置增强");
}
}
<bean id="myAspectV2" class="com.xiaoyuanzai.aspect.MyAspectV2"></bean>
<!-- aop的配置 -->
<aop:config>
<aop:pointcut expression="execution(public void com.xiaoyuanzai.service.UserService.test())" id="pointcut"/>
<aop:aspect ref="myAspectV2">
<aop:before method="asBefore" pointcut-ref="pointcut"/>
<aop:after-returning method="asAfterReturning" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
2、原生接口的AOP
public class MyMethodBeforeAdvice implements org.springframework.aop.MethodBeforeAdvice {
@Override
public void before( Method arg0, Object[] arg1, Object arg2)
throws Throwable {
System.out.println("save前置内容");
}
}
<bean id="before" class="com.xiaoyuanzai.aspect.MyMethodBeforeAdvice"></bean>
<aop:config>
<aop:pointcut expression="execution(public void com.xiaoyuanzai.service.UserService.test())" id="pointcut"/>
<aop:advisor advice-ref="before" pointcut-ref="pointcut"/>
</aop:config>
从上面demo就能很清晰看到纯POJO切面和原生接口的AOP的区别。
现在正式看一下它的findEligibleAdvisors()方法
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
/**
* 通过 通知者探测器来帮助我们找到通知,advisorRetrievalHelper在什么时候初始化的?
*/
return this.advisorRetrievalHelper.findAdvisorBeans();
}
/**
* this.advisorRetrievalHelper.findAdvisorBeans()的源码
*/
public List<Advisor> findAdvisorBeans() {
// 用来保存我们的Advisor全类名
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
//获取advisor类型的beanName
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
//若在容器中没有找到,直接返回一个空的集合
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
//默认都是true
if (isEligibleBean(name)) {
//是不是正在创建的bean
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
//不是的话
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
从上面代码可以看到,要获取到advisor需要两步操作
1、过滤并获取Advisor类型的beanName数组
2、遍历beanName数组,调用getBean()方法获取advisor列表
因为xml不常用,所以这里不深入了,有兴趣的同学自己看源码哈
2.1.2. buildAspectJAdvisors()
这里才是本文的重点
从图中很容易发现,其实就是几层循环而已。
- 先拿到所有的beanName,遍历beanName,查找被@Aspect注解的类
- 遍历@Aspect注解的类,拿到它的所有方法,看哪些方法被@Before、@After等通知注解了的(@pointcut注解排除),然后存到一个统一的list里面返回
看下buildAspectJAdvisors()源码
public List<Advisor> buildAspectJAdvisors() {
// 用于保存切面的名称类级别的缓存,用户缓存已经解析出来的切面信息
List<String> aspectNames = this.aspectBeanNames;
// 缓存字段aspectNames没有值 会在第一个单例执行后置处理器(AnnotationAwareAspectJAutoProxyCreator注册之后)的时候就会触发解析切面的操作
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 把所有beanNames拿出来遍历,判断某个bean的类型是否是Aspect
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
//true: 类型是@Aspect 切面
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
// //把beanName和class对象构建成为一个AspectMetadata(切面的注解信息)
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 如果@Aspect不是perthis、pertarget,那么一个切面只会生成一个对象(单例)
// 并且会将该切面中所对应的Advisor对象进行缓存
//为单例 bean 实现增强的 Aspect 的逻辑
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//构建切面注解的实例工厂
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 利用BeanFactoryAspectInstanceFactory来解析Aspect类
//真正去获取通知对象们
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 缓存切面所对应的所有Advisor对象
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
// 为多例 bean 增强的切面的处理逻辑
else {
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
//它不会缓存advisor, 而是缓存了factory, 需要advisor 的时候,重新调用 getAdvisors() 再生成
this.aspectFactoryCache.put(beanName, factory);
// 利用PrototypeAspectInstanceFactory来解析Aspect类
// PrototypeAspectInstanceFactory的父类为BeanFactoryAspectInstanceFactory
// 这两个Factory的区别在于PrototypeAspectInstanceFactory的构造方法中会判断切面Bean是不是原型,除此之外没有其他区别
// 所以主要就是BeanFactoryAspectInstanceFactory来负责生成切面实例对象
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 如果切面已经找到过了,那么则遍历每个切面是否缓存了对应的Advisor,如果没有缓存则进行解析得到Advisor
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
//从缓存中获取advisor
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
1、当@Aspect()是单例时,直接缓存advisor
2、当@Aspect()是perthis/pertarget时,是多例bean提供增强的切面类型,缓存的是factory,当需要advisor时,重新调用getAdvisors()生成即可
3、共同点:都是调用了this.advisorFactory.getAdvisors(factory)
4、缓存是以beanName为key去存数据
上面是通过this.advisorFactory.isAspect(beanType)来判断bean是否被@Aspect注解
进入ReflectiveAspectJAdvisorFactory的getAdvisors()看看
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
//获取我们的标记为Aspect的类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
//获取我们的切面类的名称
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
//校验我们的切面类
validate(aspectClass);
// 保证切面Bean对象只会实例化一次
// 一定要注意,这里是直接new出来一个LazySingletonAspectInstanceFactoryDecorator
// 也就是OrderService这个Bean在执行Bean生命周期过程中,会需要判断要不要进行AOP,就会找到切面,
// 发现切面如果是pertarget或perthis,那么就会进入到这个方法,就会new一个LazySingletonAspectInstanceFactoryDecorator
// 对于UserService也是一样的,在它的Bean的生命周期过程中,也会进入到这个方法,也会new一个LazySingletonAspectInstanceFactoryDecorator
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
//获取到切面类中的所有方法,但是该方法不会解析标注了@PointCut注解的方法
for (Method method : getAdvisorMethods(aspectClass)) {
//挨个去解析我们切面中的方法
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// @Aspect("pertarget(this(com.xiaoyuanzai.service.UserService))")
// @Aspect("perthis(this(com.xiaoyuanzai.service.UserService))")
// 如果是pertarget或perthis,则会多生成一个Advisor并放在最前面
// 在一个代理对象调用方法的时候,就会执行该Advisor,并且会利用lazySingletonAspectInstanceFactory来生成一个切面Bean
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// 找到哪些字段上加了@DeclareParents注解,把这些字段以及对于的注解解析封装为Advisor,生成代理对象时会把对于的接口添加到ProxyFactory中
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<>();
// 拿到切面类中所有没有加@Pointcut的方法
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
// 对方法进行排序,按注解和方法名字进行排序
if (methods.size() > 1) {
methods.sort(adviceMethodComparator);
}
return methods;
}
private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));
上面代码大意是,获取@Aspect注解的的bean的所有方法,并筛选这些方法,看看符不符合通知方法@Before、@After(排除@pointcut),符合就生成Advisor放进列表放回,我们看一下流程图
进入getAdvisor()
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 获得当前通知的 切点表达式,
// 但是注意:如果当前方法上是这么写的@After("pointcut()"),那么此时得到的Pointcut并没有去解析pointcut()得到对应的表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// expressionPointcut是pointcut
// candidateAdviceMethod承载了advice
// 将切点表达式、 和通知 封装到InstantiationModelAwarePointcutAdvisorImpl对象中
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
这里比较重要,分为两步
1、第一步通过getPointcut()方法生成AspectJExpressionPointcut对象,因为AspectJExpressionPointcut是Pointcut的子类,也就是说获取到了PointCut切面
2.第二步把AspectJExpressionPointcut作为参数传入,生成Advisor对象(InstantiationModelAwarePointcutAdvisorImpl类型),因为Advisor=Advice+PointCut,所以说在new InstantiationModelAwarePointcutAdvisorImpl()的时候实例化advice的
2.1.2.1. getPoint()
getPoint()方法核心就是实例化point,它分为两步
1、获取AspectJAnnotation实例
2、用AspectJAnnotation实例做参数,实例化一个AspectJExpressionPointcut(切点)对象
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 找到aspectJ的注解:
// @Pointcut @Around @Before @After @AfterReturning @AfterThrowing
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
// 没有注解那肯定忽略
if (aspectJAnnotation == null) {
return null;
}
// 得到一个AspectJExpressionPointcut对象
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;
}
2.1.2.1.1. 获取AspectJAnnotation实例
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;
}
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {
// 内部会去解析
return new AspectJAnnotation<>(result);
}
else {
return null;
}
}
public AspectJAnnotation(A annotation) {
this.annotation = annotation;
this.annotationType = determineAnnotationType(annotation);
try {
this.pointcutExpression = resolveExpression(annotation);
Object argNames = AnnotationUtils.getValue(annotation, "argNames");
this.argumentNames = (argNames instanceof String ? (String) argNames : "");
}
catch (Exception ex) {
throw new IllegalArgumentException(annotation + " is not a valid AspectJ annotation", ex);
}
}
//通过注解实例,获取到了注解类型和切点表达式
private AspectJAnnotationType determineAnnotationType(A annotation) {
AspectJAnnotationType type = annotationTypeMap.get(annotation.annotationType());
if (type != null) {
return type;
}
throw new IllegalStateException("Unknown annotation type: " + annotation);
}
private static Map<Class<?>, AspectJAnnotationType> annotationTypeMap = new HashMap<>(8);
static {
annotationTypeMap.put(Pointcut.class, AspectJAnnotationType.AtPointcut);
annotationTypeMap.put(Around.class, AspectJAnnotationType.AtAround);
annotationTypeMap.put(Before.class, AspectJAnnotationType.AtBefore);
annotationTypeMap.put(After.class, AspectJAnnotationType.AtAfter);
annotationTypeMap.put(AfterReturning.class, AspectJAnnotationType.AtAfterReturning);
annotationTypeMap.put(AfterThrowing.class, AspectJAnnotationType.AtAfterThrowing);
}
private String resolveExpression(A annotation) {
for (String attributeName : EXPRESSION_ATTRIBUTES) {
Object val = AnnotationUtils.getValue(annotation, attributeName);
if (val instanceof String) {
String str = (String) val;
if (!str.isEmpty()) {
return str;
}
}
}
throw new IllegalStateException("Failed to resolve expression: " + annotation);
}
private static final String[] EXPRESSION_ATTRIBUTES = new String[] {"pointcut", "value"};
看代码可能有点头疼,奉上debug截图
2.1.2.1.2. 实例化AspectJExpressionPointcut(切点)对象
第一步拿到了AspectJAnnotation,然后到第二步实例化AspectJExpressionPointcut对象
// 得到一个AspectJExpressionPointcut对象
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
//切面类信息
this.pointcutDeclarationScope = declarationScope;
if (paramNames.length != paramTypes.length) {
throw new IllegalStateException(
"Number of pointcut parameter names must match number of pointcut parameter types");
}
//参数信息
this.pointcutParameterNames = paramNames;
//参数类型
this.pointcutParameterTypes = paramTypes;
}
1、可以看到传入的三个参数中,有两个是空信息,然后调用了ajexp.setExpression(aspectJAnnotation.getPointcutExpression())就设置了切点表达式进去(expression=“pointCut()”),就这样切点的实例化结束了
2、目前只是拿到切点而已,可是我们需要进行切点匹配,有类级别和方法级别的匹配,看上去好像并不是在这里进行匹配的,那在哪里匹配呢?我们看下他的继承关系
AspectJExpressionPointcut的继承关系
由图可得,它实现Pointcut接口,而且实现了ClassFilter和MethodMathcher接口。所以说这AspectJExpressionPointcut拥有类信息匹配和方法匹配的能力!!
我们进去看看他的方法
@Override
public ClassFilter getClassFilter() {
obtainPointcutExpression();
return this;
}
@Override
public MethodMatcher getMethodMatcher() {
obtainPointcutExpression();
return this;
}
可以看到这两个方法被重写了,而obtainPointcutExpression()这个方法的作用是什么?因为前面只是拿到了切点表达式信息而已,如本文的(expression=“pointCut()”),那么这里就是匹配pointcut()里的execution配置的路径信息,这个方法就是干这个用的
进入obtainPointcutExpression()
private PointcutExpression obtainPointcutExpression() {
if (getExpression() == null) {
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
// 获取类加载器
this.pointcutClassLoader = determinePointcutClassLoader();
// 获取切点表达式信息
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
return this.pointcutExpression;
}
private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {
PointcutParser parser = initializePointcutParser(classLoader);
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
for (int i = 0; i < pointcutParameters.length; i++) {
pointcutParameters[i] = parser.createPointcutParameter(
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
}
//解析切点表达式
return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),
this.pointcutDeclarationScope, pointcutParameters);
}
public PointcutExpression parsePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters)
throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
PointcutExpressionImpl pcExpr = null;
try {
//获取到advice的配置的value的值,如本文的pointcut()
Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
//这里是根据pointcut() 获取到execution配置信息
pc = concretizePointcutExpression(pc, inScope, formalParameters);
validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts
pcExpr = new PointcutExpressionImpl(pc, expression, formalParameters, getWorld());
} catch (ParserException pEx) {
throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
} catch (ReflectionWorld.ReflectionWorldException rwEx) {
throw new IllegalArgumentException(rwEx.getMessage());
}
return pcExpr;
}
2.1.2.2. new InstantiationModelAwarePointcutAdvisorImpl
经过上面一系列操作,切点实例被创建出来了,而且还重写了getClassFilter()和getMethodMatcher(),可是还不能直接使用,需要解析pointcutExpression里的execution路径,并才能进行类/方法匹配。
还记得前面说的Advisor里会实例化advice吗,我们看一下
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect
// AspectJExpressionPointcut declaredPointcut
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 通过切点和方法信息new一个Advice对象,提醒:当前是在Advisor内部了
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
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);
}
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
//获取我们的切面类的class对象
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
//获取切面方法上的注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
//解析出来的注解信息是否为null
if (aspectJAnnotation == null) {
return null;
}
//判断这里的class对象是不是切面信息对象
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
// 记录找到了advice方法
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 按不同的注解类型得到不同的Advice
switch (aspectJAnnotation.getAnnotationType()) {
//是PointCut注解 那么就抛出异常 因为在外面传递进来的方法已经排除了pointcut的方法
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround: // @Around 环绕通知 构建AspectJAroundAdvice
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore: //前置通知 构建AspectJMethodBeforeAdvice
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter: //后置通知 AspectJAfterAdvice
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning: //返回通知 AspectJAfterReturningAdvice
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing: //异常通知 AspectJAfterThrowingAdvice
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);
}
//配置我们构建出来的通知对象
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
上面代码说简单点就是,在Advisor构造函数里实例化了advice,并把传入的切点实例做参数,一起生成Advisor实例
2.2. AbstractAdvisorAutoProxyCreator
在段落 2.1中,我们拿到了所有的advisors,然后需要这些advisors进行过滤,看看哪些advisors属于这个bean的
由此来到了粉色区域(AbstractAutoProxyCreator类)里,我们先大概浏览一下流程图,心里有个数先
由图可知,里面有类信息/方法信息匹配,一看就是前面段落 2.1 重写的那两个方法的功劳
进代码看看
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 寻找匹配的Advisor
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 找到所有的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 进行筛选,判断我们的通知能不能作用到当前的类上(切点是否命中当前Bean)
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
// 对Advisor进行排序,按Ordered接口、@Order注解进行排序
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
/**
* 判断我们候选的通知能否作用到我们当前正在创建的类上
* @param candidateAdvisors 候选的增强器
* @param beanClass 正在创建的bean的class对象
* @param beanName beanName
* @return 返回合适本类的通知器
* @see ProxyCreationContext#getCurrentProxiedBeanName()
*/
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
//用来记录当前正在创建的被代理对象的名称
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
/**
* 从候选的通知器中找到当前Bean关联的advisors
*/
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
//从线程局部变量中清楚当前正在创建的beanName的代理对象名称
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
// 如果没有通知 肯定 直接返回
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
//定义一个匹配到的增强器集合对象
List<Advisor> eligibleAdvisors = new ArrayList<>();
//循环我们候选的增强器对象
for (Advisor candidate : candidateAdvisors) {
//判断我们的增强器对象是不是实现了IntroductionAdvisor
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
//不为空
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
//判断我们的增强器对象是不是实现了IntroductionAdvisor
if (candidate instanceof IntroductionAdvisor) {
//在上面已经处理过 ,不需要处理
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
//引介增强的匹配
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
//PointcutAdvisor 类型的匹配,Spring AOP 生成的advisor,通过这种类型匹配
else if (advisor instanceof PointcutAdvisor) {
//转为PointcutAdvisor类型
PointcutAdvisor pca = (PointcutAdvisor) advisor;
//找到真正能用的增强器
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
/**
* 判断targetClass是不是和当前Pointcut匹配
* 进行类级别过滤(通过AspectJ)
*/
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
/**
* 进行方法级别过滤
*/
//如果pc.getMethodMatcher()返回TrueMethodMatcher则匹配所有方法
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
//判断匹配器是不是IntroductionAwareMethodMatcher 只有AspectJExpressionPointCut才会实现这个接口
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
//创建一个集合用于保存targetClass 的class对象
Set<Class<?>> classes = new LinkedHashSet<>();
//判断当前class是不是代理的class对象
if (!Proxy.isProxyClass(targetClass)) {
//加入到集合中去
classes.add(ClassUtils.getUserClass(targetClass));
}
//获取到targetClass所实现的接口的class对象,然后加入到集合中
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
//循环所有的class对象
for (Class<?> clazz : classes) {
//通过class获取到所有的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
//循环我们的方法
for (Method method : methods) {
//通过methodMatcher.matches来匹配我们的方法
if (introductionAwareMethodMatcher != null ?
// 通过切点表达式进行匹配 AspectJ方式
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
// 通过方法匹配器进行匹配 内置aop接口方式
methodMatcher.matches(method, targetClass)) {
// 只要有1个方法匹配上了就创建代理
return true;
}
}
}
return false;
}
在上面的代码中就知道了我们获得的一堆advisors是如何一个个跟bean匹配的。
2.3. AbstractAutoProxyCreator
在前面经过一系列骚操作,获取到符合当前bean的advisors了,接下来就轮到生成代理对象了,看下流程图清晰点
我们从getBean()的后置处理器banPostProcessor开始讲起
/**
* AbstractAutoProxyCreator类
* 正常进行AOP的地方
*/
@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;
}
进入wrapIfNecessary()方法
因为第一步的specificInterceptors[]数组其实就是advisors,需要传到第二步的createProxy()
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建一个代理对象工厂
ProxyFactory proxyFactory = new ProxyFactory();
// 复制配置参数
proxyFactory.copyFrom(this);
//为proxyFactory设置创建jdk代理还是cglib代理
// 如果设置了 <aop:aspectj-autoproxy proxy-target-class="true"/>不会进if,说明强制使用cglib
if (proxyFactory.isProxyTargetClass()) {
if (Proxy.isProxyClass(beanClass)) {
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// 如果没有指定,那么则判断是不是应该进行cglib代理(判断BeanDefinition中是否指定了要用cglib)
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 是否进行jdk动态代理,如果当前beanClass实现了某个接口,那么则会使用JDK动态代理
evaluateProxyInterfaces(beanClass, proxyFactory);// 判断beanClass有没有实现接口
}
}
// 将commonInterceptors和specificInterceptors整合再一起
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 在这一步会去判断advisors中是否存在IntroductionAdvisor,如果存在则会把对应的interface添加到proxyFactory中去
proxyFactory.addAdvisors(advisors); // 向ProxyFactory中添加advisor
proxyFactory.setTargetSource(targetSource); // 被代理的对象
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
// 代表之前是否筛选advise.
// 因为继承了AbstractAdvisorAutoProxyCreator , 并且之前调用了findEligibleAdvisors进行筛选, 所以是true
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
// 生成代理对象
return proxyFactory.getProxy(classLoader);
}
//ProxyFactory类
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
可以看到createAopProxy().getProxy(classLoader)有两种代理模式,cglib和jdk代理
我们先看下ProxyFactory类的继承关系
createAopProxy()是ProxyCreatorSupport类实现的,也就是说ProxyFactory实际上把工作给到了他爸ProxyCreatorSupport去做
//ProxyCreatorSupport类
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 默认为DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
进入DefaultAopProxyFactory类
/**
*
* @param config 用来为我们指定我们advisor信息
* 该方法用来创建我们的代理对象
* 我们的targetClass对象实现了接口,且 ProxyTargetClass 没有指定强制的走cglib代理,那么就是创建jdk代理
* 我们代理的类没有实现接口,那么会直接走cglib代理
* 若我们 ProxyTargetClass 指定为false 且代理类是接口才会走jdk代理 否在我们还是cglib代理
* @return
* @throws AopConfigException
*/
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 如果ProxyFactory的isOptimize为true,Spring认为cglib比jdk动态代理要快
// 或者isProxyTargetClass为true,
// 或者被代理对象没有实现接口,
// 或者只实现了SpringProxy这个接口
// 那么则利用Cglib进行动态代理,但如果被代理类是接口,或者被代理类已经是进行过JDK动态代理而生成的代理类了则只能进行JDK动态代理
// 其他情况都会进行JDK动态代理,比如被代理类实现了除SpringProxy接口之外的其他接口
if (!NativeDetector.inNativeImage() &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//targetClass是接口 使用的就是jdk代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
//cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
//动态代理
return new JdkDynamicAopProxy(config);
}
}
这里就很清晰了,创建对象的任务交给jdk或者cglib去做,下篇文章再详细讲解创建代理对象的过程了
最后:作为图灵学院一份子,学习来源于周瑜和徐庶两位我特别敬重的老师,站在巨人的肩膀上增加了自己的理解,本文不以商业化为目的,纯个人学习使用
参考文献:
Spring AOP 第二篇-Spring 如何解析切面获取切点,通知和生成代理对象_spring怎么判断要走切面_Cison chen的博客-CSDN博客