死磕Spring AOP系列2:剖析Bean处理器之BeanNameAutoProxyCreator

简介:

通过前一篇<死磕Spring AOP系列1:编程式实现AOP>,学习了Spring对代理的底层支持,认识了ProxyFactory对象,及从类设计层面认识了PointCut&Advisor&Advice&Interceptor,还认识了AdvisorChainFactory对象,知道了底层Advisor的底层链式结构。但是,上篇我们仅仅是通过Spring编程式实现的"AOP"效果,这种方式,实际开发时,如果这样用就太LOW了。今天,主要认识一个生成代理相关的BeanPostProcessor,它是一个相对比较简单的和代理相关的BeanPostProcessor之一,对研究Spring 容器生成代理对象逻辑,容易上手,达到深入浅出的目的。

本篇文章的主要内容

  1. 使用BeanNameAutoProxyCreator,做一个简单的代码演示

  2. 剖析BeanNameAutoProxyCreator设计

  3. 理解InstantiationAwareBeanPostProcessor

  4. 分析一些关键点方法


1.BeanNameAutoProxyCreator实现“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
<? 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.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >
       < property  name = "beanNames" >
          < list >
             < value >userService</ value >
          </ list >
 
       </ property >
       < property  name = "interceptorNames" >
          < list >
             < value >loggerBeforeAdvice</ value >
          </ list >
       </ property >
    </ bean >
</ beans >


Main

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

=======保存更新日志=========
$$$$$$执行业务逻辑$$$$$


代码很简单,不需要解释。

2.剖析BeanNameAutoProxyCreator设计

类层次结构图

wKioL1dSGVyDcgQ0AAA9cPz_1GQ925.png

下面,简单概要描述下每个接口的作用

类&接口
作用
Ordered
定义顺序的,影响Processor的执行顺序,默认为“LOWEST_PRECEDENCE”,可以自己指定
Aware*类
感知接口,与Spring容器沟通的手段
*BeanPostProcessor
影响spring Bean的生命周期,在对应生命周期中调用,是生成代理对象的入口
AopInfrastructureBean 表示该类是Spring AOP支持对象,仅仅是个标识
ProxyConfig
是一个类,保存了代理配置元信息,影响代理生成行为

类图

wKiom1dSGt_yXG02AAAs4W1o6uw618.png


结合上一篇 死磕Spring AOP系列1:编程式实现AOP 的讲解,我们知道了Spring生成代理时,需要2个重要的信息,一个是源对象targetSource,一个是Advisor列表。

抛出2个假设问题

  1. Spring应该是从Spring容器中,根据咱们声明的beanNames属性,当成源对象,然后代理包装。

  2. Advisor列表,也是从Spring容器中获取,和interceptorNames相关。

3.剖析BeanNameAutoProxyCreator实现

3.1Spring怎么完成BeanName的匹配的。

1
2
3
4
5
6
7
8
9
10
11
12
/**
  *1.通过分析注释,我们知道了beanNames 支持模糊匹配,比如"*", e.g. "myBean,tx*"。
  *2.支持FactoryBean(包含 factory-bean prefix "&": 比如: "&myFactoryBean".
  *
  */
public  void  setBeanNames(String[] beanNames) {
    Assert.notEmpty(beanNames,  "'beanNames' must not be empty" );
    this .beanNames =  new  ArrayList<String>(beanNames.length);
    for  (String mappedName : beanNames) {
       this .beanNames.add(StringUtils.trimWhitespace(mappedName));
    }
}

beanNames是如何被使用的呢

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
public  abstract  class  AbstractAutoProxyCreator  extends  ProxyConfig
       implements  SmartInstantiationAwareBeanPostProcessor, BeanClassLoaderAware, BeanFactoryAware,
       Ordered, AopInfrastructureBean {
       //抽象方法,不同的AbstractAutoProxyCreator 实现类,根据策略分别实现。
       //提供实现:AbstractAdvisorAutoProxyCreator OR BeanNameAutoProxyCreator
       // 被BeanPostProcessor 生命周期回调方法中调用
     protected  abstract  Object[] getAdvicesAndAdvisorsForBean(
          Class<?> beanClass, String beanName, TargetSource customTargetSource)  throws  BeansException;
 
}
 
protected  Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
    if  ( this .beanNames !=  null ) {
        //循环遍历beanNames
       for  (String mappedName :  this .beanNames) {
          if  (FactoryBean. class .isAssignableFrom(beanClass)) {
             if  (!mappedName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
                continue ;
             }
             mappedName = mappedName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
          }
          //逐个匹配
          if  (isMatch(beanName, mappedName)) {
             return  PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
          }
          BeanFactory beanFactory = getBeanFactory();
          if  (beanFactory !=  null ) {
             String[] aliases = beanFactory.getAliases(beanName);
             //匹配aliases
             for  (String alias : aliases) {
                if  (isMatch(alias, mappedName)) {
                   return  PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
                }
             }
          }
       }
    }
    return  DO_NOT_PROXY;
}
//
protected  boolean  isMatch(String beanName, String mappedName) {
    return  PatternMatchUtils.simpleMatch(mappedName, beanName);
}

3.2Advisor列表初始化

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
//1
public  Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)  throws  BeansException {
...
    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    if  (beanName !=  null ) {
       TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
       if  (targetSource !=  null ) {
          this .targetSourcedBeans.put(beanName, Boolean.TRUE);
          Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
          Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
          this .proxyTypes.put(cacheKey, proxy.getClass());
          return  proxy;
       }
    }
 
    return  null ;
}
 
//2
protected  Object createProxy(
       Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
 
    ProxyFactory proxyFactory =  new  ProxyFactory();
...
 
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    for  (Advisor advisor : advisors) {
       proxyFactory.addAdvisor(advisor);
    }
...
    return  proxyFactory.getProxy( this .proxyClassLoader);
}
 
//3
protected  Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
    // Handle prototypes correctly...
    Advisor[] commonInterceptors = resolveInterceptorNames();
 
    List<Object> allInterceptors =  new  ArrayList<Object>();
    if  (specificInterceptors !=  null ) {
       allInterceptors.addAll(Arrays.asList(specificInterceptors));
       if  (commonInterceptors !=  null ) {
          if  ( this .applyCommonInterceptorsFirst) { //分支
             allInterceptors.addAll( 0 , Arrays.asList(commonInterceptors));
          }
          else  {
             allInterceptors.addAll(Arrays.asList(commonInterceptors));
          }
       }
    }
 
    Advisor[] advisors =  new  Advisor[allInterceptors.size()];
    for  ( int  i =  0 ; i < allInterceptors.size(); i++) {
       advisors[i] =  this .advisorAdapterRegistry.wrap(allInterceptors.get(i));
    }
    return  advisors;
}
 
//4
//完成到interceptorNames到Advisor的转换
private  Advisor[] resolveInterceptorNames() {
    ConfigurableBeanFactory cbf = ( this .beanFactory  instanceof  ConfigurableBeanFactory) ?
          (ConfigurableBeanFactory)  this .beanFactory :  null ;
    List<Advisor> advisors =  new  ArrayList<Advisor>();
    for  (String beanName :  this .interceptorNames) {
       if  (cbf ==  null  || !cbf.isCurrentlyInCreation(beanName)) {
          Object next =  this .beanFactory.getBean(beanName);
          advisors.add( this .advisorAdapterRegistry.wrap(next));
       }
    }
    return  advisors.toArray( new  Advisor[advisors.size()]);
}

需要提的是advisorAdapterRegistry,看图说话,Spring抽象了一层将advisor和interceptor很好的做了分离,各得其所。

wKiom1dSIW6xM0cRAAAc9vfEWIc204.png

死磕到这儿,应该明白了Spring容器是如何完成如何完成代理工作的,应该非常清楚了。还有一个问题需要解决,Spring容器的生成代理的入口在那儿?。如果对SpringIOC底层机制和Spring 对象生命周期非常熟悉的话,非常自然的联想到BeanPostProcessor.

4.BeanPostProcessor回顾

wKioL1dSJGGwYJtYAAKQbmsXKC4990.png

理解BeanPostProcessor,最要结合bean的生命周期一同观看

wKiom1dSI7azw004AAXUz17Jm_Q205.png

通过对比,我们可以知道在spring bean的构造过程中,spring容器会调用对应的BeanPostProcessor。一般调用时机包括:初始化,实例化等。

那么接下来,咱们就继续剖析BeanNameAutoProxyCreator,只不过要把它当成一个普通的BeanPostProcessor。

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
//没有逻辑,不需要关注
public  Object postProcessBeforeInitialization(Object bean, String beanName) {
    return  bean;
}
 
/**
  * Create a proxy with the configured interceptors if the bean is
  * identified as one to proxy by the subclass.
  * @see #getAdvicesAndAdvisorsForBean
  * 通过注释,我们可以知道创建代理,就在这儿。生成入口已经找到了
  */
public  Object postProcessAfterInitialization(Object bean, String beanName)  throws  BeansException {
    if  (bean !=  null ) {
       Object cacheKey = getCacheKey(bean.getClass(), beanName);
       if  (! this .earlyProxyReferences.containsKey(cacheKey)) {
          return  wrapIfNecessary(bean, beanName, cacheKey);
       }
    }
    return  bean;
}
/**
* 包装,完成代理对象生成
*/
protected  Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if  (beanName !=  null  &&  this .targetSourcedBeans.containsKey(beanName)) {
       return  bean;
    }
    if  (Boolean.FALSE.equals( this .advisedBeans.get(cacheKey))) {
       return  bean;
    }
    if  (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
       this .advisedBeans.put(cacheKey, Boolean.FALSE);
       return  bean;
    }
 
    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName,  null );
    if  (specificInterceptors != DO_NOT_PROXY) {
       this .advisedBeans.put(cacheKey, Boolean.TRUE);
       Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors,  new  SingletonTargetSource(bean));
       this .proxyTypes.put(cacheKey, proxy.getClass());
       return  proxy;
    }
 
    this .advisedBeans.put(cacheKey, Boolean.FALSE);
    return  bean;
}


总结:虽然BeanNameAutoProxyCreator是个很简单的BeanPostProcessor,功能LOW的很少有人问津,但对我们研究Spring AOP容器的底层实现非常有必要,麻雀虽小五脏俱全。通过分析,我们可以关注几个概念。1.Interceptors,Advisor,advisorAdapterRegistry。其实PointCut对象,如果你DUBUG的时候,也能看到,只不过咱们没有讲。因为咱们没有配置,但Spring已经给我们默认生成了一个:TruePointcut。

到了这里,Spring AOP 基本流程也串的差不多了,但总有些遗憾。Spring非常强大的表达式支持没有看到,自动检索Bean没有看到,强大快捷的配置没有看到。现在看不到不要紧,以后随着死磕Spring AOP的深入,会看到的。




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

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