Spring AOP 的proxy详解
2008-12-10 15:05
330 查看
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>
view plaincopy to clipboardprint?
<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);
}
view plaincopy to clipboardprint?
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";
}
}
view plaincopy to clipboardprint?
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
下图是 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>
view plaincopy to clipboardprint?
<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.
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);
}
view plaincopy to clipboardprint?
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);
}
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";
}
}
view plaincopy to clipboardprint?
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";
}
}
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
相关文章推荐
- spring AOP切面表达式详解
- 【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3
- 深入浅出Spring(三) AOP详解
- 【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3
- Spring 之AOP AspectJ切入点语法详解
- 详解使用Spring Boot的AOP处理自定义注解
- »Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
- [Spring学习笔记 5 ] Spring AOP 详解1
- Spring中的IOC和AOP详解
- Spring AOP详解
- 15_传智播客Spring2.5视频教程_使用JDK中的Proxy技术实现AOP功能 2
- Spring、AOP详解
- Spring AOP 详解[转]
- 在Eclipse RCP中使用Spring AOP/ProxyFactory的问题
- 详解Spring Boot中使用AOP统一处理Web请求日志
- Spring配置项之<aop:aspectj-autoproxy />
- spring 配置 <aop:aspectj-autoproxy expose-proxy=""/>
- Spring AOP-编程的方式创建代理类(ProxyFactoryBean)
- Spring实现AOP的几种方式详解
- 详解在Spring中如何使用AspectJ来实现AOP