欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 前端技术 > javascript >内容正文

javascript

Spring AOP 的proxy详解

发布时间:2025/5/22 javascript 52 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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 :      

  •    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />   
  •  <bean id="defaultPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" scope="prototype">   
  •         <property name="pointcut" ref="fooPointcut"/>   
  •         <property name="advice" ref="fooAdvice"/>   
  • </bean>      
  •   
  • <bean id="fooAdvice" class="com.mycompany.FooAdvice" scope="prototype" />   
  •   
  • <bean id="fooPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">   
  •         <property name="patterns">   
  •             <list>   
  •                 <value>com.mycompany.FooService.*</value>   
  •             </list>   
  •         </property>   
  •     </bean>   
  •     
  • [java] view plaincopy
  •     
  •    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />  
  •  <bean id="defaultPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" scope="prototype">  
  •         <property name="pointcut" ref="fooPointcut"/>  
  •         <property name="advice" ref="fooAdvice"/>  
  • </bean>     
  •   
  • <bean id="fooAdvice" class="com.mycompany.FooAdvice" scope="prototype" />  
  •   
  • <bean id="fooPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">  
  •         <property name="patterns">  
  •             <list>  
  •                 <value>com.mycompany.FooService.*</value>  
  •             </list>  
  •         </property>  
  •     </bean>  
  •     


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

    深度话题

    1. MethodInterceptor 如何被包装成 Advisor ?

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

  • public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {   
  •   if (adviceObject instanceof Advisor) {   
  •     return (Advisor) adviceObject;   
  •   }   
  •   if (!(adviceObject instanceof Advice)) {   
  •     hrow new UnknownAdviceTypeException(adviceObject);   
  •   }   
  •   Advice advice = (Advice) adviceObject;   
  •   if (advice instanceof MethodInterceptor) {   
  •    // So well-known it doesn't even need an adapter.   
  •    return new DefaultPointcutAdvisor(advice);   
  •   }   
  •   for (int i = 0; i < this.adapters.size(); i++) {   
  •    / Check that it is supported.   
  •                                AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);   
  • if (adapter.supportsAdvice(advice)) {   
  •                                  return new DefaultPointcutAdvisor(advice);   
  •  }   
  • }   
  •   throw new UnknownAdviceTypeException(advice);   
  •                     }   
  •            
  • [java] view plaincopy
  • public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {  
  •   if (adviceObject instanceof Advisor) {  
  •     return (Advisor) adviceObject;  
  •   }  
  •   if (!(adviceObject instanceof Advice)) {  
  •     hrow new UnknownAdviceTypeException(adviceObject);  
  •   }  
  •   Advice advice = (Advice) adviceObject;  
  •   if (advice instanceof MethodInterceptor) {  
  •    // So well-known it doesn't even need an adapter.  
  •    return new DefaultPointcutAdvisor(advice);  
  •   }  
  •   for (int i = 0; i < this.adapters.size(); i++) {  
  •    / Check that it is supported.  
  •                                AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);  
  • if (adapter.supportsAdvice(advice)) {  
  •                                  return new DefaultPointcutAdvisor(advice);  
  •  }  
  • }  
  •   throw new UnknownAdviceTypeException(advice);  
  •                     }  
  •            


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

  •     class TruePointcut implements Pointcut, Serializable {   
  •   
  •     public static final TruePointcut INSTANCE = new TruePointcut();   
  •        
  •     /**  
  •      * Enforce Singleton pattern.  
  •      */  
  •     private TruePointcut() {   
  •     }   
  •   
  •     public ClassFilter getClassFilter() {   
  •         return ClassFilter.TRUE;   
  •     }   
  •   
  •     public MethodMatcher getMethodMatcher() {   
  •         return MethodMatcher.TRUE;   
  •     }   
  •        
  •     /**  
  •      * Required to support serialization. Replaces with canonical  
  •      * instance on deserialization, protecting Singleton pattern.  
  •      * Alternative to overriding <code>equals()</code>.  
  •      */  
  •     private Object readResolve() {   
  •         return INSTANCE;   
  •     }   
  •   
  •     public String toString() {   
  •         return "Pointcut.TRUE";   
  •     }   
  •   
  • }   
  •        
  •       
  • [java] view plaincopy
  •     class TruePointcut implements Pointcut, Serializable {  
  •   
  •     public static final TruePointcut INSTANCE = new TruePointcut();  
  •       
  •     /** 
  •      * Enforce Singleton pattern. 
  •      */  
  •     private TruePointcut() {  
  •     }  
  •   
  •     public ClassFilter getClassFilter() {  
  •         return ClassFilter.TRUE;  
  •     }  
  •   
  •     public MethodMatcher getMethodMatcher() {  
  •         return MethodMatcher.TRUE;  
  •     }  
  •       
  •     /** 
  •      * Required to support serialization. Replaces with canonical 
  •      * instance on deserialization, protecting Singleton pattern. 
  •      * Alternative to overriding <code>equals()</code>. 
  •      */  
  •     private Object readResolve() {  
  •         return INSTANCE;  
  •     }  
  •   
  •     public String toString() {  
  •         return "Pointcut.TRUE";  
  •     }  
  •   
  • }  
  •       
  •       


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

    转载于:https://www.cnblogs.com/hanxue112253/p/3878181.html

    总结

    以上是生活随笔为你收集整理的Spring AOP 的proxy详解的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。