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>
[java] view plaincopy
  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. 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. }
[java] view plaincopy
  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. }
[java] view plaincopy
  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

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

Spring AOP 的proxy详解相关推荐

  1. 跟着小马哥学系列之 Spring AOP(Advisor 详解)

    学好路更宽,钱多少加班. --小马哥 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间< ...

  2. Spring AOP实现原理详解之Cglib代理实现

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

  3. Spring AOP 功能使用详解

    前言 AOP 既熟悉又陌生,了解过 Spring 人的都知道 AOP 的概念,即面向切面编程,可以用来管理一些和主业务无关的周边业务,如日志记录,事务管理等:陌生是因为在工作中基本没有使用过,AOP ...

  4. 跟着小马哥学系列之 Spring AOP(AbstractAutoProxyCreator 详解)

    学成路更宽,吊打面试官. --小马哥 版本修订 2021.5.19:去除目录 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了 ...

  5. Spring AOP 与代理详解

    SpringBoot 系列教程 - 源码地址:https://github.com/laolunsi/spring-boot-examples 大家知道我现在还是一个 CRUD 崽,平时用 AOP 也 ...

  6. Spring AOP切点表达式详解

    1. 简介 面向对象编程,也称为OOP(即Object Oriented Programming)最大的优点在于能够将业务模块进行封装,从而达到功能复用的目的.通过面向对象编程,不同的模板可以相互组装 ...

  7. Spring AOP之PointCut详解

    一.PointCut接口 /** Copyright 2002-2012 the original author or authors.** Licensed under the Apache Lic ...

  8. Spring之Joinpoint类详解

    说明 Joinpoint是AOP的连接点.一个连接点代表一个被代理的方法.我们从源码角度看连接点有哪些属性和功能. 源码 /** Copyright 2002-2016 the original au ...

  9. Spring包含JAR的详解

    一.Spring 常用包的说明 spring.jar :  包含有完整发布模块的单个jar 包.但是不包括mock.jar, aspects.jar, spring-portlet.jar, and ...

最新文章

  1. JavaScript学习 九、事件
  2. 015PHP文件处理——文件处理flock 文件锁定 pathinfo realpath tmpfile tempname
  3. node 更新_Node.js 15 正式发布,14 将支持到 2023 年
  4. 资源权限操作-添加资源权限
  5. pandas之shift()函数
  6. leetcode初级算法2.旋转数组
  7. 蓝桥杯第五届省赛JAVA真题----n级台阶
  8. “我,程序员,33岁,距离退休,只剩2年了!”
  9. python sys.path
  10. mysql 5.6 my.cnf配置文件_mysql 5.6 my.cnf 配置
  11. DAN疼之后上些基础知识---自定义HttpModule和httpHandler
  12. 静态网页HTML知识点归纳
  13. 国标GB28181协议国标平台EasyGBS客户端作为上级平台如何跟下级海康8700平台对接?
  14. 音视频技术开发周刊 85期
  15. win10删除账户文件夹(C:\Users\***)后,无法登录账户的解决方法
  16. 《经济学通识》:人类会受到“东西不够、生命有限、相互依赖、需要协调”四方面的限制,影响我们的衣食住行
  17. 2.3Linux中的日志管理
  18. 【自动驾驶】高级驾驶辅助系统(ADAS)
  19. git版本控制以及分支管理
  20. linux系统发qq邮箱文件,Linux打印文件和发送邮件

热门文章

  1. 【坑爹微信】微信JSSDK图片上传问题和解决
  2. Web负载均衡学习笔记之K8S内Ngnix微服务服务超时问题
  3. UOJ.386.[UNR #3]鸽子固定器(贪心 链表)
  4. hdu 2255 奔小康赚大钱--KM算法模板
  5. javascript时间处理
  6. 【安全牛学习笔记】SQLMAP- 自动注入
  7. Pig的安装和简单使用
  8. 编写一段代码,实现在控制台输入一组数据后,排序后再控制台输出
  9. 近期window7x64 打补丁之后IE11x64无法启动
  10. 200多个js技巧代码(4)