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>

以上配置将自动代理容器中所有 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. ; 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. }
  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. }

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

  1. class TruePointcut implements Pointcut, Serializable {
  2. public static final 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. public static final 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. }

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

Spring AOP 的proxy详解的更多相关文章

  1. Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现

    前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的.本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所 ...

  2. Spring框架系列(10) - Spring AOP实现原理详解之AOP代理的创建

    上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor).本文在此基 ...

  3. Spring框架系列(11) - Spring AOP实现原理详解之Cglib代理实现

    我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理.@pdai Spring框架系列 ...

  4. Spring框架系列(12) - Spring AOP实现原理详解之JDK代理实现

    上文我们学习了SpringAOP Cglib动态代理的实现,本文主要是SpringAOP JDK动态代理的案例和实现部分.@pdai Spring框架系列(12) - Spring AOP实现原理详解 ...

  5. Spring Aop底层原理详解

    Spring Aop底层原理详解(来源于csdn:https://blog.csdn.net/baomw)

  6. Spring AOP 入门实例详解

    目录 AOP概念 AOP核心概念 Spring对AOP的支持 基于Spring的AOP简单实现 基于Spring的AOP使用其他细节 AOP概念 AOP(Aspect Oriented Program ...

  7. Spring框架系列(8) - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

    上文,我们看了IOC设计要点和设计结构:以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的:容器中存放的是Bean的定义即Be ...

  8. Spring框架系列(6) - Spring IOC实现原理详解之IOC体系结构设计

    在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解.本文将帮助你站在设计者的角度去看IOC最顶层的结构设计.@pdai Spring框架系列(6) - Spring IOC实现原理详解 ...

  9. Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程

    上文,我们看了IOC设计要点和设计结构:紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的. ...

随机推荐

  1. dojo表格分页之各个参数代表的意义(一)

    下面是dojo表格分页参数代表的意义 //每页可以显示10/15/20/25/30条记录 (1)pageSizes: [10, 15, 20, 25,30], //每页显示的记录从多少到多少,共多少条 ...

  2. 【mongodb系统学习之十】mongodb查询(一)

    十.mongodb查询:find ;查询时条件中不能引用文档中其他键的值: 1).查询数据库全部数据:语法db.collectionName.find();默认只显示前20条,如图: 2).按条件查询 ...

  3. Error Code: 1360 - Trigger does not existQuery

    1.错误描述 Query: DROP TRIGGER `t_sert_cs_approve` Error occured at:2015-04-12 13:37:32 Line no.:1 Error ...

  4. org.apache.jasper.JasperException

    1.错误描述 2014-7-13 17:20:50 org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() ...

  5. ASP.NET CORE的Code Fist后Models更改了怎么办?

    上次我写到MVC的code fist后,自动生成数据库并自动生成web页面了 点击打开链接 那么随着项目需求的逐步明确,model变化了怎么办呢?其实和上次一样的,有两条关键的语句要记住 Add-Mi ...

  6. 浏览器之window对象--javascript

    window对象代表打开的浏览器窗口,是Web浏览器所有内容的主容器.window对象是整个对象链条结构的最高层,是其他对象的父对象,在调用window对象的方法和属性时,可以省略window对象的引 ...

  7. Unity3D 引擎基础 C# (数据结构入门) Unity3D 界面 UI(NGUI)(动画系统,导航系统)(委托与事件,常用设计模式)

    Geomagic Sculpt 2016.2 Windows Software 11个月前 (01-17) 0评论 Geomagic Sculpt 触觉式三维设计 触碰您的设计使用三维工具做三维设计. ...

  8. P2500 - 【DP合集】背包 bound

    题面 Description N 种物品,第 i 种物品有 s i 个,单个重量为 w i ,单个价值为 v i .现有一个限重为 W 的背包,求能容 纳的物品的最大总价值. Input 输入第一行二 ...

  9. kali使用Fluxion钓鱼WiFi

    先介绍一下这个软件 这个软件是一个可以生成一个钓鱼WiFi的软件,可以伪装成一个正常的WiFi,但是是没有密码的,但是其他信息都是一样的,一旦开启这个攻击,正常的那个AP就无法正常连接,只能连到这个伪 ...

  10. 解决Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project autotest_fchtgl: Compilation failure的方法

    在碰到maven install 发现报错 Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.2:comp ...