Spring Aop(十四)——Aop自动创建代理对象的原理
转发地址:https://www.iteye.com/blog/elim-2398725
Aop自动创建代理对象的原理
我们在使用Spring Aop时,通常Spring会自动为我们创建目标bean的代理对象,以使用对应的Advisor。前提是我们在使用Spring Aop时是使用的<aop:config/>或<aop:aspectj-autoproxy/>,这是因为当我们在applicationContext.xml文件中通过<aop:config/>的形式定义需要使用Aop的场景时,Spring会自动为我们添加AspectjAwareAdvisorAutoProxyCreator类型的bean;而我们定义了<aop:aspectj-autoproxy/>时,Spring会默认为我们添加AnnotationAwareAspectjAutoProxyCreator类型的bean。Spring中在bean实例化后能够对bean对象进行包装的是BeanPostProcessor,AspectjAwareAdvisorAutoProxyCreator和AnnotationAwareAspectjAutoProxyCreator都是实现了BeanPostProcessor接口的。AnnotationAwareAspectjAutoProxyCreator的父类是AspectjAwareAdvisorAutoProxyCreator,而AspectjAwareAdvisorAutoProxyCreator的父类是AbstractAdvisorAutoProxyCreator,AbstractAdvisorAutoProxyCreator的父类是实现了BeanPostProcessor接口的AbstractAutoProxyCreator。它们的核心逻辑都是在bean初始化后找出bean容器中所有的能够匹配当前bean的Advisor,找到了则将找到的Advisor通过ProxyFactory创建该bean的代理对象返回。AspectjAwareAdvisorAutoProxyCreator在寻找候选的Advisor时会找到bean容器中所有的实现了Advisor接口的bean,而AnnotationAwareAspectjAutoProxyCreator则在AspectjAwareAdvisorAutoProxyCreator的基础上增加了对标注了@Aspect的bean的处理,会附加上通过@Aspect标注的bean中隐式定义的Advisor。所以这也是为什么我们在使用@Aspect标注形式的Spring Aop时需要在applicationContext.xml文件中添加<aop:aspectj-autoproxy/>。既然AspectjAwareAdvisorAutoProxyCreator和AnnotationAwareAspectjAutoProxyCreator都会自动扫描bean容器中的Advisor,所以当我们使用了<aop:config/>或<aop:aspectj-autoproxy/>形式的Aop定义时,如果因为某些原因光通过配置满足不了你Aop的需求,而需要自己实现Advisor接口时(一般是实现PointcutAdvisor接口),那这时候你只需要把自己的Advisor实现类,定义为Spring的一个bean即可。如果你在applicationContext.xml中没有定义<aop:config/>或<aop:aspectj-autoproxy/>,那你也可以直接在applicationContext.xml中直接定义AspectjAwareAdvisorAutoProxyCreator或AnnotationAwareAspectjAutoProxyCreator类型的bean,效果也是一样的。其实为了能够在创建目标bean的时候能够自动创建基于我们自定义的Advisor实现类的代理对象,我们的bean容器中只要有AbstractAutoProxyCreator类型的bean定义即可,当然了你实现自己的BeanPostProcessor,在其postProcessAfterInitialization方法中创建自己的代理对象也是可以的。但是本着不重复发明轮子的原则,我们尽量使用官方已经提供好的实现即可。AbstractAutoProxyCreator是继承自ProxyConfig的,所以我们在定义AbstractAutoProxyCreator子类的bean时,我们也可以手动的定义一些ProxyConfig中包含的属性,比如proxyTargetClass、exposeProxy等。AbstractAutoProxyCreator的子类除了AspectjAwareAdvisorAutoProxyCreator和AnnotationAwareAspectjAutoProxyCreator外,我们可用的还有BeanNameAutoProxyCreator和DefaultAdvisorAutoProxyCreator。
BeanNameAutoProxyCreator
BeanNameAutoProxyCreator可以用来定义哪些bean可与哪些Advisor/Advice绑定,以生成对应的代理对象。需要绑定的bean是通过beanNames属性来指定的,对应的是bean的名称,其中可以包含“*”号,表示任意字符,比如“abc*”则匹配任意名称以“abc”开始的bean;需要绑定的Advisor/Advice是通过interceptorNames来指定的,如果指定的是Advisor,那么是否可生成基于该Advisor的代理需要对应的bean能够匹配对应Advisor(PointcutAdvisor类型)的Pointcut;如果指定的是Advice,则该Advice会被包含在Pointcut恒匹配的Advisor中,即能够与所有的bean绑定生成对应的代理,且会对所有的方法调用起作用。 指定interceptorNames时是不能使用通配符的,只能精确的指定需要应用的Advisor/Advice对应的bean名称。
<bean id="userService" class="com.elim.learn.spring.aop.service.UserServiceImpl"/>
<bean id="myService" class="com.elim.learn.spring.aop.service.MyService"/> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!-- 匹配userService和所有名称以my开头的bean -->
<property name="beanNames" value="userService, my*"/>
<!-- interceptorNames中不能使用通配符,只能是精确匹配,
即精确指定Advisor/Advice的bean名称 -->
<property name="interceptorNames" value="logBeforeAdvice, myAdvisor "/>
</bean> <bean id="logBeforeAdvice"
class="com.elim.learn.spring.aop.advice.LogBeforeAdvice" /> <bean id="myAdvisor" class="com.elim.learn.spring.aop.advisor.MyAdvisor"/>
如上就是一个使用BeanNameAutoProxyCreator建立指定的bean基于指定的Advisor/Advice的代理对象的示例。示例中我们指定interceptorNames时特意应用了一个Advisor实现和一个Advice实现。Advice会应用于所有绑定的bean的所有方法调用,而Advisor只会应用于其中的Pointcut能够匹配的方法调用。这里的源码我就不提供了,有兴趣的朋友可以自己试试。
DefaultAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator的父类也是AbstractAdvisorAutoProxyCreator。DefaultAdvisorAutoProxyCreator的作用是会默认将bean容器中所有的Advisor都取到,如果有能够匹配某一个bean的Advisor存在,则会基于能够匹配该bean的所有Advisor创建对应的代理对象。需要注意的是DefaultAdvisorAutoProxyCreator在创建bean的代理对象时是不会考虑Advice的,只是Advisor。如上面的示例中,如果我们希望所有的bean都能够自动的与匹配的Advisor进行绑定生成对应的代理对象,那么我们可以调整配置如下。
<bean id="userService" class="com.elim.learn.spring.aop.service.UserServiceImpl"/>
<bean id="myService" class="com.elim.learn.spring.aop.service.MyService"/> <bean
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> <bean id="myAdvisor" class="com.elim.learn.spring.aop.advisor.MyAdvisor"/>
使用DefaultAdvisorAutoProxyCreator时可能我们并不希望为所有的bean定义都自动应用bean容器中的所有Advisor,而只是希望自动创建基于部分Advisor的代理对象。这个时候如果我们期望应用自动代理的Advisor的bean定义的名称都是拥有固定的前缀时,则我们可以应用DefaultAdvisorAutoProxyCreator的setAdvisorBeanNamePrefix(String)指定需要应用的Advisor的bean名称的前缀,同时需要通过setUsePrefix(boolean)指定需要应用这种前缀匹配机制。如我们的bean容器中有两个Advisor定义,一个bean名称是“myAdvisor”,一个bean名称是“youAdvisor”,如果只期望自动创建基于bean名称以“my”开始的Advisor的代理,则可以进行如下配置。
<bean
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<property name="usePrefix" value="true" />
<!-- 匹配所有bean名称以my开始的Advisor -->
<property name="advisorBeanNamePrefix" value="my" />
</bean>
(注:本文是基于Spring4.1.0所写,Elim写于2017年5月12日)
Spring Aop(十四)——Aop自动创建代理对象的原理的更多相关文章
- 自己实现简单的AOP(四)自动初始化代理对象
		
前面三篇随笔,已经完成了AOP的核心功能,但 代理对象的初始化还是有些麻烦,本文将解决该问题. Demo 片段如下: public class HomeController : Controller ...
 - Spring Aop(十三)——ProxyFactoryBean创建代理对象
		
转发地址:https://www.iteye.com/blog/elim-2398673 ProxyFactoryBean创建代理对象 ProxyFactoryBean实现了Spring的Factor ...
 - Spring 中如何自动创建代理(spring中的三种自动代理创建器)
		
Spring 提供了自动代理机制,可以让容器自动生成代理,从而把开发人员从繁琐的配置中解脱出来 . 具体是使用 BeanPostProcessor 来实现这项功能. 这三种自动代理创建器 为:Bean ...
 - Spring AOP 自动创建代理
		
Spring为我们提供了自动代理机制,让容器为我们自动生成代理,把我们从烦琐的配置工作中解放出来,在内部,Spring 使用BeanPostProcessor自动地完成这项工作. 1.实现 ...
 - 死磕Spring之AOP篇 - Spring AOP自动代理(三)创建代理对象
		
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...
 - spring学习 十四 注解AOP  通知传递参数
		
我们在对切点进行增强时,不建议对切点进行任何修改,因此不加以使用@PointCut注解打在切点上,尽量只在Advice上打注解(Before,After等),如果要在通知中接受切点的参数,可以使用Jo ...
 - Spring AOP 源码分析 - 创建代理对象
		
1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...
 - Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理
		
AOP代理对象的创建 AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现: protected Object applyBea ...
 - spring aop 源码分析(三) @Scope注解创建代理对象
		
一.源码环境的搭建: @Component @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON,proxyMode = ScopedP ...
 
随机推荐
- vue 之 render 函数不能渲染非全局自定义函数-方案
			
import customCom from 'xxx.vue' render: (h) => { return h(customCom) }
 - Spring boot dubbo+zookeeper 搭建------基于gradle项目的消费端与服务端分离实战
			
1. Dubbo简介 Dubbo是Alibaba开源的分布式框架,是RPC模式的一种成熟的框架,优点是可以与Spring无缝集成,应用到我们的后台程序中.具体介绍可以查看Dubbo官网. 2. Why ...
 - 9、Spring Boot 2.x 集成 Thymeleaf
			
1.9 Spring Boot 2.x 集成 Thymeleaf 完整源码: Spring-Boot-Demos 1.9.1 在pom中引入依赖 <dependency> <grou ...
 - PHP mysqli_connect() 函数
			
打开一个到 MySQL 服务器的新的连接: mysqli_connect(host,username,password,dbname,port,socket); <?php $con=mysql ...
 - Oracle 后台进程(三)LGWR进程
			
一.LGWR进程简介 LGWR,是Log Writer的缩写,也是一种后台进程.主要负责将日志缓冲内容写到磁盘的在线重做日志文件或组中.DBWn将dirty块写到磁盘之前,所有与buffer修改相关的 ...
 - Gradle 如何打包 Spring Boot 如何不添加版本代码
			
在 Gradle 中如何在打包的 Jar 中不包含版本代码? 在 bootJar 中,使用下面的代码进行打包不包含版本代码. archiveFileName = "${archiveBase ...
 - OI 常用模板 手写
			
线性筛素数 (例题 洛谷P3383) bool p[50000010]; int cnt = 0; int prime[10000010]; inline void init() { int N = ...
 - maven-jetty插件配置时,webdefault.xml的取得和修改
			
取得 没必要去下载一个jetty客户端去找webdefault.xml了. 可以去maven的本地仓库找到 \org\eclipse\jetty\jetty-webapp\版本号\ 里面的jar文件, ...
 - 注解之 @RestController 和 @RequestMapping
			
Controller 是 Spring 中最基本的组件,主要处理用户交互,一般每个业务逻辑都会有一个 Controller,供用户请求接口进行数据访问:@RequestMapping 注解用于绑定UR ...
 - input上传mp3格式文件,预览并且获取时间
			
<input type="file" id="file" name="file" class="upfile" o ...