zoukankan      html  css  js  c++  java
  • Spring AOP 的proxy详解

    spring 提供了多种不同的方案实现对 bean 的 aop proxy, 包括 ProxyFactoryBean, 便利的 TransactionProxyFactoryBean 以及 AutoProxyCreator 等,
    下图是 proxy class diagram 以供参考

    这里重点说一下最常用的 ProxyFactoryBean, TransactionProxyFactoryBean, BeanNameAutoProxyCreator, DefaultAdvisorAutoProxyCreator 的联系和区别

    1. ProxyFactoryBean : 使用率最高的 proxy 方式, 它通过配置 interceptorNames 属性决定加入哪些 advisor (method interceptor 将会被自动包装成 advisor, 下文将描述这个细节),
    注意是 "interceptorNames" 而不是 "interceptors",

    原因是 ProxyFactoryBean 可能返回非 singleton 的 proxy 实例, 而 advisior 可能也是非 singleton 的,

    因此不能通过 interceptor reference 来注入

    2. TransactionProxyFactoryBean : 特定用于 transaction proxy, 注意其 super class 是 AbstractSingletonProxyFactoryBean, 也就是说,

    TransactionProxyFactoryBean 永远无法返回非 singleton 的 proxy 实例 !!!

    如果你需要非 singleton 的 proxy 实例, 请考虑使用 ProxyFactoryBean.

    3. BeanNameAutoProxyCreator : 故名思义, 根据 bean name 进行 auto proxy, bean name 的 match 规则参见 org.springframework.util.PatternMatchUtils

    4. DefaultAdvisorAutoProxyCreator : 更强大的 auto proxy creator, 强大之处在于它会 cahce 容器中所有注册的 advisor, 然后搜索容器中所有的 bean ,
    如果某个 bean 满足 advisor 中的 Pointcut, 那么将会被自动代理, 与 BeanNameAutoProxyCreator 相比, 省去了配置 beanNames 的工作,

    引用:
    eg :      

    1.    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />   
    2.  <bean id="defaultPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" scope="prototype">   
    3.         <property name="pointcut" ref="fooPointcut"/>   
    4.         <property name="advice" ref="fooAdvice"/>   
    5. </bean>      
    6.   
    7. <bean id="fooAdvice" class="com.mycompany.FooAdvice" scope="prototype" />   
    8.   
    9. <bean id="fooPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">   
    10.         <property name="patterns">   
    11.             <list>   
    12.                 <value>com.mycompany.FooService.*</value>   
    13.             </list>   
    14.         </property>   
    15.     </bean>   
    16.     
    1.     
    2.    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />  
    3.  <bean id="defaultPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" scope="prototype">  
    4.         <property name="pointcut" ref="fooPointcut"/>  
    5.         <property name="advice" ref="fooAdvice"/>  
    6. </bean>     
    7.   
    8. <bean id="fooAdvice" class="com.mycompany.FooAdvice" scope="prototype" />  
    9.   
    10. <bean id="fooPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">  
    11.         <property name="patterns">  
    12.             <list>  
    13.                 <value>com.mycompany.FooService.*</value>  
    14.             </list>  
    15.         </property>  
    16.     </bean>  
    17.     



    以上配置将自动代理容器中所有 com.mycompany.FooService 类型的 bean, 并拦截其所有方法

    深度话题

    1. MethodInterceptor 如何被包装成 Advisor ?

    在 AdvisorAdapterRegistry#wrap(Object) 方法中实现, code as below

    1. public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {   
    2.   if (adviceObject instanceof Advisor) {   
    3.     return (Advisor) adviceObject;   
    4.   }   
    5.   if (!(adviceObject instanceof Advice)) {   
    6.     hrow new UnknownAdviceTypeException(adviceObject);   
    7.   }   
    8.   Advice advice = (Advice) adviceObject;   
    9.   if (advice instanceof MethodInterceptor) {   
    10.    // So well-known it doesn't even need an adapter.   
    11.    return new DefaultPointcutAdvisor(advice);   
    12.   }   
    13.   for (int i = 0; i < this.adapters.size(); i++) {   
    14.    / Check that it is supported.   
    15.                                AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);   
    16. if (adapter.supportsAdvice(advice)) {   
    17.                                  return new DefaultPointcutAdvisor(advice);   
    18.  }   
    19. }   
    20.   throw new UnknownAdviceTypeException(advice);   
    21.                     }   
    22.            
    1. public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {  
    2.   if (adviceObject instanceof Advisor) {  
    3.     return (Advisor) adviceObject;  
    4.   }  
    5.   if (!(adviceObject instanceof Advice)) {  
    6.     hrow new UnknownAdviceTypeException(adviceObject);  
    7.   }  
    8.   Advice advice = (Advice) adviceObject;  
    9.   if (advice instanceof MethodInterceptor) {  
    10.    // So well-known it doesn't even need an adapter.  
    11.    return new DefaultPointcutAdvisor(advice);  
    12.   }  
    13.   for (int i = 0; i < this.adapters.size(); i++) {  
    14.    / Check that it is supported.  
    15.                                AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);  
    16. if (adapter.supportsAdvice(advice)) {  
    17.                                  return new DefaultPointcutAdvisor(advice);  
    18.  }  
    19. }  
    20.   throw new UnknownAdviceTypeException(advice);  
    21.                     }  
    22.            



    从代码可以看到, 如果 adviceObject(也就是 interceptorNames 对应的 bean) 不是 advisor
    而是 MethodInterceptor 或 Advice, 那么 spring 将其包装成 DefaultPointcutAdvisor,
    而 DefaultPointcutAdvisor 中定义的 Pointcut 是 TruePointcut :

    1.     class TruePointcut implements Pointcut, Serializable {   
    2.   
    3.     public static final TruePointcut INSTANCE = new TruePointcut();   
    4.        
    5.     /**  
    6.      * Enforce Singleton pattern.  
    7.      */  
    8.     private TruePointcut() {   
    9.     }   
    10.   
    11.     public ClassFilter getClassFilter() {   
    12.         return ClassFilter.TRUE;   
    13.     }   
    14.   
    15.     public MethodMatcher getMethodMatcher() {   
    16.         return MethodMatcher.TRUE;   
    17.     }   
    18.        
    19.     /**  
    20.      * Required to support serialization. Replaces with canonical  
    21.      * instance on deserialization, protecting Singleton pattern.  
    22.      * Alternative to overriding <code>equals()</code>.  
    23.      */  
    24.     private Object readResolve() {   
    25.         return INSTANCE;   
    26.     }   
    27.   
    28.     public String toString() {   
    29.         return "Pointcut.TRUE";   
    30.     }   
    31.   
    32. }   
    33.        
    34.       
    1.     class TruePointcut implements Pointcut, Serializable {  
    2.   
    3.     public static final TruePointcut INSTANCE = new TruePointcut();  
    4.       
    5.     /** 
    6.      * Enforce Singleton pattern. 
    7.      */  
    8.     private TruePointcut() {  
    9.     }  
    10.   
    11.     public ClassFilter getClassFilter() {  
    12.         return ClassFilter.TRUE;  
    13.     }  
    14.   
    15.     public MethodMatcher getMethodMatcher() {  
    16.         return MethodMatcher.TRUE;  
    17.     }  
    18.       
    19.     /** 
    20.      * Required to support serialization. Replaces with canonical 
    21.      * instance on deserialization, protecting Singleton pattern. 
    22.      * Alternative to overriding <code>equals()</code>. 
    23.      */  
    24.     private Object readResolve() {  
    25.         return INSTANCE;  
    26.     }  
    27.   
    28.     public String toString() {  
    29.         return "Pointcut.TRUE";  
    30.     }  
    31.   
    32. }  
    33.       
    34.       



    也就是说, MethodInterceptor 和 Advice 被包装成的 Advisor 将会匹配容器中的所有 bean,
    所以, 永 远不要在 DefaultAdvisorAutoProxyCreator 的 interceptorNames 中引用一个 Advice, 那将会使容器中所有的 bean 被自动代理!!! 此时应该考虑使用 BeanNameAutoProxyCreator

  • 相关阅读:
    每日博客
    每日博客
    每日博客
    每日博客
    每日博客
    每日博客
    每日博客
    每日博客
    centos7 systemctl 管理MySQL
    Postgresqlz之迁移数据pg_dump
  • 原文地址:https://www.cnblogs.com/hanxue112253/p/3878181.html
Copyright © 2011-2022 走看看