死磕Spring AOP系列3:剖析Bean处理器之DefaultAdvisorAutoProxyCreator

简介:

这是<死磕Spring AOP系列>的第三篇。经过前面的讲解,已经掌握了以下知识点

  1. Spring AOP的底层支持,是基于ProxyFactory+ProxyConfig+Advisor生成的

  2. Spring容器的代理对象生成:在Bean生命周期过长中调用BeanPostProcessor,将对象进行包装,生成代理对象。

  3. Advisor的指定:不管编程式指定,还是自动匹配指定。虽然形式不同,但本质是相同的。

如果,还对上面的问题存疑,请回看以上内容。

本篇主要对剖析另外一个BeanPostProcessor,他就是DefaultAdvisorAutoProxyCreator,他是BeanNameAutoProxyCreator的升级版。形象点说:如果ProxyFactory是弓箭的话,代表原始,BeanNameAutoProxyCreator就是步枪,需要自己装配,DefaultAdvisorAutoProxyCreator就是自动步枪了,Spring可以完成自动匹配的部分工作了。

本章主要内容

  1. 使用DefaultAdvisorAutoProxyCreator,完成一个“AOP"例子,讲解下如何配置

  2. 对比BeanNameAutoProxyCreator,对DefaultAdvisorAutoProxyCreator进行剖析

  3. 分析DefaultAdvisorAutoProxyCreator的Advisor的匹配过程

  4. 体会自动化


1.使用DefaultAdvisorAutoProxyCreator,完成一个“AOP"例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
  *模拟业务接口
  */
public  interface  UserService {
     public  void  updateUser();
}
  
/**
  *模拟具体业务
  */
public  class  UserServiceImpl  implements  UserService{
  
     @Override
     public  void  updateUser() {
         System.out.println( "$$$$$$执行业务逻辑$$$$$" );
     }
}
  
/**
  * 模拟切面1
  */
public  class  SecurityInterceptor  implements  MethodInterceptor {
     @Override
     public  Object invoke(MethodInvocation methodInvocation)  throws  Throwable {
         System.out.println( "==========执行安全校验====================" );
         return  methodInvocation.proceed();
     }
}
  
/**
  * 模拟切面2
  */
public  class  LoggerBeforeAdvice  implements  MethodBeforeAdvice {
     @Override
     public  void  before(Method method, Object[] args, Object target)  throws  Throwable {
         System.out.println( "=======保存更新日志=========" );
     }
}

xml(proxy_test.xml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<? xml  version = "1.0"  encoding = "UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
 
< beans >
    < bean  class = "org.springaop.chap01.UserServiceImpl"  id = "userService" ></ bean >
    < bean  class = "org.springaop.chap01.LoggerBeforeAdvice"  id = "loggerBeforeAdvice" ></ bean >
    < bean  class = "org.springaop.chap01.SecurityInterceptor"  id = "securityInterceptor" ></ bean >
 
 
    <!-- 自动代理所有的advisor -->
    < bean  class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" >
       < property  name = "usePrefix"  value = "true" ></ property >
       < property  name = "advisorBeanNamePrefix"  value = "advisor" ></ property >
    </ bean >
 
    < bean  id = "advisor1"  class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" >
       < property  name = "pattern" >
          < value >.*update.*</ value >   <!-- 业务实现方法名匹配 -->
       </ property >
       < property  name = "advice" >
          < ref  bean = "loggerBeforeAdvice" />
       </ property >
    </ bean >
 
    < bean  id = "advisor2"  class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" >
       < property  name = "pattern" >
          < value >.*update.*</ value >   <!-- 业务实现方法名匹配 -->
       </ property >
       < property  name = "advice" >
          < ref  bean = "securityInterceptor" />
       </ property >
    </ bean >
</ beans >

Main

1
2
3
4
5
6
7
8
9
public  class  ContextMain {
     public  static  void  main(String[] args) {
         ApplicationContext ctx =  new  ClassPathXmlApplicationContext( "org/springaop/chap03/proxy_test.xml" );
         UserService userService =(UserService) ctx.getBean( "userService" );
//        UserService userService2 =(UserService) ctx.getBean("userService2");
         userService.updateUser();
//        userService2.updateUser();
     }
}

执行结果

=======保存更新日志=========
==========执行安全校验====================
$$$$$$执行业务逻辑$$$$$


说明:usePrefix和advisorBeanNamePrefix配合使用,如果usePrefix设置为false,advisorBeanNamePrefix设置没有作用。通过上面的设置配置,advisor2和advisor都有效果。

2.剖析DefaultAdvisorAutoProxyCreator类

2.1 结构层次图

wKiom1dSRECQVFl4AACratmjUuY978.png


可知,DefaultAdvisorAutoProxyCreator,BeanNameAutoProxyCreator是AbstractAutoProxyCreator的子类。通过前面讲解,知道AbstractAutoProxyCreator有个抽象方法。

方法声明如下

1
2
3
4
//是否被代理?返回interceptors
//Return whether the given bean is to be proxied, what additional advices (e.g. AOP Alliance interceptors) and advisors to apply.
protected  abstract  Object[] getAdvicesAndAdvisorsForBean(
       Class<?> beanClass, String beanName, TargetSource customTargetSource)  throws  BeansException;

DefaultAdvisorAutoProxyCreator 和BeanNameAutoProxyCreator分别实现各自逻辑。BeanNameAutoProxyCreator的实现不再赘述,在死磕Spring AOP系列2已经讲过,代码很简单。

2.2 剖析getAdvicesAndAdvisorsForBean方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public  abstract  class  AbstractAdvisorAutoProxyCreator  extends  AbstractAutoProxyCreator {
...
protected  Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
    List advisors = findEligibleAdvisors(beanClass, beanName);
    if  (advisors.isEmpty()) {
       return  DO_NOT_PROXY;
    }
    return  advisors.toArray();
}
 
protected  List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors(); //获取所有的Advisors
    //获取可以应用于beanName的Advisor(逻辑尽在此)
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if  (!eligibleAdvisors.isEmpty()) {
       eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return  eligibleAdvisors;
}
//Find all candidate Advisors to use in auto-proxying.
protected  List<Advisor> findCandidateAdvisors() {
    //委托给BeanFactoryAdvisorRetrievalHelper处理
    return  this .advisorRetrievalHelper.findAdvisorBeans();
}
 
}
public  class  BeanFactoryAdvisorRetrievalHelper {
     public  List<Advisor> findAdvisorBeans() {
 
...
           if  (advisorNames ==  null ) {
               //获取容器中声明的Advisor
              // Do not initialize FactoryBeans here: We need to leave all regular beans
              // uninitialized to let the auto-proxy creator apply to them!
              advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this .beanFactory, Advisor. class true false );
...
        }
        if  (advisorNames.length ==  0 ) {
           return  new  LinkedList<Advisor>();
        }
     
        List<Advisor> advisors =  new  LinkedList<Advisor>();
        for  (String name : advisorNames) {
            //判断返回
           if  (isEligibleBean(name) && ! this .beanFactory.isCurrentlyInCreation(name)) {
              try  {
                 advisors.add( this .beanFactory.getBean(name, Advisor. class ));
              }
              catch  (BeanCreationException ex) {
                 ...
                 throw  ex;
              }
           }
        }
        return  advisors;
     }
}

通过层层抽丝剥茧,定位到了AopUtils.findAdvisorsThatCanApply,负责具体的Advisor匹配工作。

3.剖析AopUtils.findAdvisorsThatCanApply方法,(匹配逻辑)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
protected  List<Advisor> findAdvisorsThatCanApply(
       List<Advisor> candidateAdvisors, Class beanClass, String beanName) {
 
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try  {
       return  AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    }
    finally  {
       ProxyCreationContext.setCurrentProxiedBeanName( null );
    }
}
 
public  static  List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if  (candidateAdvisors.isEmpty()) {
       return  candidateAdvisors;
    }
    List<Advisor> eligibleAdvisors =  new  LinkedList<Advisor>();
    for  (Advisor candidate : candidateAdvisors) { //遍历
       if  (candidate  instanceof  IntroductionAdvisor && canApply(candidate, clazz)) {
       //是否IntroductionAdvisor
          eligibleAdvisors.add(candidate);
       }
    }
    boolean  hasIntroductions = !eligibleAdvisors.isEmpty();
    for  (Advisor candidate : candidateAdvisors) {
       if  (candidate  instanceof  IntroductionAdvisor) {
          // already processed
          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);
    }
    else  if  (advisor  instanceof  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" );
    if  (!pc.getClassFilter().matches(targetClass)) {
       return  false ;
    }
 
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    IntroductionAwareMethodMatcher introductionAwareMethodMatcher =  null ;
    if  (methodMatcher  instanceof  IntroductionAwareMethodMatcher) {
       introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    }
 
    Set<Class> classes =  new  HashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
    classes.add(targetClass);
    for  (Class<?> clazz : classes) {
       Method[] methods = clazz.getMethods();
       for  (Method method : methods) {
          if  ((introductionAwareMethodMatcher !=  null  &&
                introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
                methodMatcher.matches(method, targetClass)) { //methodMatcher具体完成匹配
             return  true ;
          }
       }
    }
 
    return  false ;
}


wKioL1dSUh-BaDsIAABPQ2m8W1U171.png

通过图得知Advisor,持有Advice的聚合信息和PointCut对象,而PointCut接口持有MethodMatcher。

最后MethodMatcher完成方法匹配工作。以当前例子为例,AbstractRegexpMethodPointcut同时也是MethodMatcher.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public  abstract  class  AbstractRegexpMethodPointcut  extends  StaticMethodMatcherPointcut
       implements  Serializable {
public  boolean  matches(Method method, Class targetClass) {
    return  ((targetClass !=  null  && matchesPattern(targetClass.getName() +  "."  + method.getName())) ||
          matchesPattern(method.getDeclaringClass().getName() +  "."  + method.getName()));
}
}
 
protected  boolean  matchesPattern(String signatureString) {
    for  ( int  i =  0 ; i <  this .patterns.length; i++) {
       boolean  matched = matches(signatureString, i);
       if  (matched) {
          for  ( int  j =  0 ; j <  this .excludedPatterns.length; j++) {
             boolean  excluded = matchesExclusion(signatureString, j);
             if  (excluded) {
                return  false ;
             }
          }
          return  true ;
       }
    }
    return  false ;
}
 
public  class  JdkRegexpMethodPointcut  extends  AbstractRegexpMethodPointcut {
/**
  * Returns {@code true} if the {@link Pattern} at index {@code patternIndex}
  * matches the supplied candidate {@code String}.
  */
@Override
protected  boolean  matches(String pattern,  int  patternIndex) {
    Matcher matcher =  this .compiledPatterns[patternIndex].matcher(pattern);
    return  matcher.matches();
}
 
/**
  * Returns {@code true} if the exclusion {@link Pattern} at index {@code patternIndex}
  * matches the supplied candidate {@code String}.
  */
@Override
protected  boolean  matchesExclusion(String candidate,  int  patternIndex) {
    Matcher matcher =  this .compiledExclusionPatterns[patternIndex].matcher(candidate);
    return  matcher.matches();
}
 
 
/**
  * Compiles the supplied {@code String[]} into an array of
  * {@link Pattern} objects and returns that array.
  */
private  Pattern[] compilePatterns(String[] source)  throws  PatternSyntaxException {
    Pattern[] destination =  new  Pattern[source.length];
    for  ( int  i =  0 ; i < source.length; i++) {
       destination[i] = Pattern.compile(source[i]);
    }
    return  destination;
}
}

4.自动化

比起BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator有一个非常优越的地方。那就是advisor已有了自动匹配方法的能力。具体实现逻辑,通过上面的分析就是正则表达式的使用。其实很简单,确定一个方法是否被应用于advice,其实就是讲方法的签名字符串与定义PointCut的pattern进行匹配。今天提到的JdkRegexpMethodPointcut,只是实现之一。另外一个更强大的PointCut是什么?下次再说。



本文转自 randy_shandong 51CTO博客,原文链接:http://blog.51cto.com/dba10g/1786057,如需转载请自行联系原作者

相关文章
|
23天前
|
缓存 Java Spring
Spring 框架中 Bean 的生命周期
Spring 框架中 Bean 的生命周期
30 1
|
1月前
|
XML Java 开发者
Spring Boot中的bean注入方式和原理
Spring Boot中的bean注入方式和原理
52 0
|
28天前
|
设计模式 Java Maven
Spring Aop 底层责任链思路实现-springaopdi-ceng-ze-ren-lian-si-lu-shi-xian
Spring Aop 底层责任链思路实现-springaopdi-ceng-ze-ren-lian-si-lu-shi-xian
34 1
|
7天前
|
Java 数据库连接 开发者
浅谈Spring的Bean生命周期
浅谈Spring的Bean生命周期
17 1
|
12天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
19 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
21天前
|
XML Java Maven
Spring之Aop的注解使用
Spring之Aop的注解使用
|
22天前
|
XML Java 程序员
作为Java程序员还不知道Spring中Bean创建过程和作用?
作为Java程序员还不知道Spring中Bean创建过程和作用?
14 0
|
26天前
|
Java Spring
Spring 如何实现 AOP
Spring 如何实现 AOP
17 0
|
26天前
|
XML 缓存 Java
天天用 Spring,bean 实例化原理你懂吗
天天用 Spring,bean 实例化原理你懂吗
17 0
|
1月前
|
Java 编译器 程序员
Spring AOP 和 AspectJ 的比较
Spring AOP 和 AspectJ 的比较
37 0

热门文章

最新文章