码迷,mamicode.com
首页 > 编程语言 > 详细

Spring AOP 学习记录2

时间:2020-04-11 20:46:47      阅读:83      评论:0      收藏:0      [点我收藏+]

标签:targe   步骤   code   问题   epo   tar   ESS   static   put   

主题

补充学习一下一些关于Spring AOP的理解

 

怎么找到当前Bean可以哪些advisor应用

技术图片

 

在当前Bean被AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization方法处理的过程中

技术图片

 

 

会需要找到当前Bean可以被应用到的所有advisor.

 技术图片

 

 

 看代码也知道大致的步骤:

1.findCandidateAdvisors 找到所有的advisor

2.findAdvisorsThatCanApply 过滤出可以使用的advisor

 

findCandidateAdvisors

如何找到所有advisor?

 1 /**
 2      * Look for AspectJ-annotated aspect beans in the current bean factory,
 3      * and return to a list of Spring AOP Advisors representing them.
 4      * <p>Creates a Spring Advisor for each AspectJ advice method.
 5      * @return the list of {@link org.springframework.aop.Advisor} beans
 6      * @see #isEligibleBean
 7      */
 8     public List<Advisor> buildAspectJAdvisors() {
 9         List<String> aspectNames = this.aspectBeanNames;
10 
11         if (aspectNames == null) {
12             synchronized (this) {
13                 aspectNames = this.aspectBeanNames;
14                 if (aspectNames == null) {
15                     List<Advisor> advisors = new ArrayList<>();
16                     aspectNames = new ArrayList<>();
17                     String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
18                             this.beanFactory, Object.class, true, false);
19                     for (String beanName : beanNames) {
20                         if (!isEligibleBean(beanName)) {
21                             continue;
22                         }
23                         // We must be careful not to instantiate beans eagerly as in this case they
24                         // would be cached by the Spring container but would not have been weaved.
25                         Class<?> beanType = this.beanFactory.getType(beanName);
26                         if (beanType == null) {
27                             continue;
28                         }
29                         if (this.advisorFactory.isAspect(beanType)) {
30                             aspectNames.add(beanName);
31                             AspectMetadata amd = new AspectMetadata(beanType, beanName);
32                             if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
33                                 MetadataAwareAspectInstanceFactory factory =
34                                         new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
35                                 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
36                                 if (this.beanFactory.isSingleton(beanName)) {
37                                     this.advisorsCache.put(beanName, classAdvisors);
38                                 }
39                                 else {
40                                     this.aspectFactoryCache.put(beanName, factory);
41                                 }
42                                 advisors.addAll(classAdvisors);
43                             }
44                             else {
45                                 // Per target or per this.
46                                 if (this.beanFactory.isSingleton(beanName)) {
47                                     throw new IllegalArgumentException("Bean with name ‘" + beanName +
48                                             "‘ is a singleton, but aspect instantiation model is not singleton");
49                                 }
50                                 MetadataAwareAspectInstanceFactory factory =
51                                         new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
52                                 this.aspectFactoryCache.put(beanName, factory);
53                                 advisors.addAll(this.advisorFactory.getAdvisors(factory));
54                             }
55                         }
56                     }
57                     this.aspectBeanNames = aspectNames;
58                     return advisors;
59                 }
60             }
61         }
62 
63         if (aspectNames.isEmpty()) {
64             return Collections.emptyList();
65         }
66         List<Advisor> advisors = new ArrayList<>();
67         for (String aspectName : aspectNames) {
68             List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
69             if (cachedAdvisors != null) {
70                 advisors.addAll(cachedAdvisors);
71             }
72             else {
73                 MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
74                 advisors.addAll(this.advisorFactory.getAdvisors(factory));
75             }
76         }
77         return advisors;
78     }

BF中取到所有的BeanName,并遍历.对于每个BeanName,找到对应的Type(Class).再去找它这个类是否有Aspect.class的注解

技术图片

 

 

 从中我们可以看出我们如果要使用AOP有什么样的条件:

1.这个Aspect的类应该要被当做Bean.不然BF中里没有这个Bean的定义.不管是在XML里直接定义BeanDifination还是@Component都OK.

2.这个类应该要有@Aspect.不然怎么知道这个是一个aspect呢.(其实还有一种是compiledByAjc(clazz)..没用过.不清楚怎么用)

 

找到了Aspect的类以后只要提取其中的advisor即可. List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

大致核心如下:

对于类的每个没有标记@PointCut的方法

1         for (Method method : getAdvisorMethods(aspectClass)) {
2             Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
3             if (advisor != null) {
4                 advisors.add(advisor);
5             }
6         }
 1     private List<Method> getAdvisorMethods(Class<?> aspectClass) {
 2         final List<Method> methods = new ArrayList<>();
 3         ReflectionUtils.doWithMethods(aspectClass, method -> {
 4             // Exclude pointcuts
 5             if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
 6                 methods.add(method);
 7             }
 8         }, ReflectionUtils.USER_DECLARED_METHODS);
 9         methods.sort(METHOD_COMPARATOR);
10         return methods;
11     }

 

找到这个方法上的Aspect注解(@before..@after...@around...).从中提取出pointcut的表达式即可.

Advisor = advise(你的asperct类里的方法) + pointcut(表达式)

 1     @Override
 2     @Nullable
 3     public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
 4             int declarationOrderInAspect, String aspectName) {
 5 
 6         validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
 7 
 8         AspectJExpressionPointcut expressionPointcut = getPointcut(
 9                 candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
10         if (expressionPointcut == null) {
11             return null;
12         }
13 
14         return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
15                 this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
16     }
 1     @Nullable
 2     private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
 3         AspectJAnnotation<?> aspectJAnnotation =
 4                 AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
 5         if (aspectJAnnotation == null) {
 6             return null;
 7         }
 8 
 9         AspectJExpressionPointcut ajexp =
10                 new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
11         ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
12         if (this.beanFactory != null) {
13             ajexp.setBeanFactory(this.beanFactory);
14         }
15         return ajexp;
16     }
 1     /**
 2      * Find and return the first AspectJ annotation on the given method
 3      * (there <i>should</i> only be one anyway...).
 4      */
 5     @SuppressWarnings("unchecked")
 6     @Nullable
 7     protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
 8         for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
 9             AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
10             if (foundAnnotation != null) {
11                 return foundAnnotation;
12             }
13         }
14         return null;
15     }
1     private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
2             Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

最后封装成InstantiationModelAwarePointcutAdvisorImpl并返回.

 

findAdvisorsThatCanApply

这里没有太多神奇的操作.

找到所有的advisor以后就是判断每个advisor能不能作用到当前的类上. 怎么判断的? 之前是提出了pointcut的expression.那这里使用这个expr去和类比较一下即可.

 1     public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
 2         if (advisor instanceof IntroductionAdvisor) {
 3             return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
 4         }
 5         else if (advisor instanceof PointcutAdvisor) {
 6             PointcutAdvisor pca = (PointcutAdvisor) advisor;
 7             return canApply(pca.getPointcut(), targetClass, hasIntroductions);
 8         }
 9         else {
10             // It doesn‘t have a pointcut so we assume it applies.
11             return true;
12         }
13     }

Advisor委托MethodMatcher去做对应的match.

具体调用比较复杂..我也没有仔细去看...

 

AOP本类方法掉用本类方法不生效咋办

这个问题可能经常会遇到.我相信80%出现的情况是一个操作数据库的service上的方法a上有@Transaction, 然后方法b是个很一般的方法.b会调用a.然后发现事务没生效.

 

Spring AOP 学习记录2

标签:targe   步骤   code   问题   epo   tar   ESS   static   put   

原文地址:https://www.cnblogs.com/abcwt112/p/12681799.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!