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>
- <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>
<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.
- returnnew 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)) {
- returnnew DefaultPointcutAdvisor(advice);
- }
- }
- thrownew UnknownAdviceTypeException(advice);
- }
- 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.
- returnnew 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)) {
- returnnew DefaultPointcutAdvisor(advice);
- }
- }
- thrownew UnknownAdviceTypeException(advice);
- }
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 {
- publicstaticfinal 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";
- }
- }
- class TruePointcut implements Pointcut, Serializable {
- publicstaticfinal 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";
- }
- }
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