1. 程式人生 > >Spring AOP 的proxy詳解

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. <bean id="fooAdvice"class="com.mycompany.FooAdvice" scope="prototype" />   
  7. <bean id="fooPointcut"class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">   
  8.         <property name="patterns">   
  9.             <list>   
  10.                 <value>com.mycompany.FooService.*</value>   
  11.             </list>   
  12.         </property>   
  13.     </bean>   
  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. <bean id="fooAdvice"class="com.mycompany.FooAdvice" scope="prototype" />   
  7. <bean id="fooPointcut"class="org.springframework.aop.support.JdkRegexpMethodPointcut" scope="prototype">   
  8.         <property name="patterns">   
  9.             <list>   
  10.                 <value>com.mycompany.FooService.*</value>   
  11.             </list>   
  12.         </property>   
  13.     </bean>   
      
	      <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
  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. returnnew 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. returnnew DefaultPointcutAdvisor(advice);   
  18.  }   
  19. }   
  20. thrownew UnknownAdviceTypeException(advice);   
  21.                     }   
  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. returnnew 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. returnnew DefaultPointcutAdvisor(advice);   
  18.  }   
  19. }   
  20. thrownew UnknownAdviceTypeException(advice);   
  21.                     }   
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 :
  1. class TruePointcut implements Pointcut, Serializable {   
  2. publicstaticfinal TruePointcut INSTANCE = new TruePointcut();   
  3. /**  
  4.      * Enforce Singleton pattern.  
  5.      */
  6. private TruePointcut() {   
  7.     }   
  8. public ClassFilter getClassFilter() {   
  9. return ClassFilter.TRUE;   
  10.     }   
  11. public MethodMatcher getMethodMatcher() {   
  12. return MethodMatcher.TRUE;   
  13.     }   
  14. /**  
  15.      * Required to support serialization. Replaces with canonical  
  16.      * instance on deserialization, protecting Singleton pattern.  
  17.      * Alternative to overriding <code>equals()</code>.  
  18.      */
  19. private Object readResolve() {   
  20. return INSTANCE;   
  21.     }   
  22. public String toString() {   
  23. return"Pointcut.TRUE";   
  24.     }   
  25. }   
  1. class TruePointcut implements Pointcut, Serializable {   
  2. publicstaticfinal TruePointcut INSTANCE = new TruePointcut();   
  3. /**  
  4.      * Enforce Singleton pattern.  
  5.      */
  6. private TruePointcut() {   
  7.     }   
  8. public ClassFilter getClassFilter() {   
  9. return ClassFilter.TRUE;   
  10.     }   
  11. public MethodMatcher getMethodMatcher() {   
  12. return MethodMatcher.TRUE;   
  13.     }   
  14. /**  
  15.      * Required to support serialization. Replaces with canonical  
  16.      * instance on deserialization, protecting Singleton pattern.  
  17.      * Alternative to overriding <code>equals()</code>.  
  18.      */
  19. private Object readResolve() {   
  20. return INSTANCE;   
  21.     }   
  22. public String toString() {   
  23. return"Pointcut.TRUE";   
  24.     }   
  25. }   
         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