SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator
本文将对SpringAop中如何为AspectJ切面类创建自动代理的过程作下简单的分析,阅读本文前需要对AOP的Spring相关解析有所了解,具体可见Spring源码情操陶冶-AOP之ConfigBeanDefinitionParser解析器
官方注释
注释内容如下
/**
* {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator}
* subclass that exposes AspectJ's invocation context and understands AspectJ's rules
* for advice precedence when multiple pieces of advice come from the same aspect.
*
* @author Adrian Colyer
* @author Juergen Hoeller
* @author Ramnivas Laddad
* @since 2.0
*/
从注释上可知此类是org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator抽象类的继承类,主要为AspectJ切面服务。具体的针对如何创建代理,肯定是在父类中实现了,我们在此研究下父类。
AbstractAutoProxyCreator-AOP代理实现的抽象父类
继承结构上为extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware,而其中的SmartInstantiationAwareBeanPostProcessor是beanPostProcessor接口的子类,此处注意下此接口。下面分析的内容建立在spring在实例化bean对象的时候会调用beanPostProcessor的公有接口。
AbstractAutoProxyCreator#postProcessAfterInitialization()-创建代理的入口函数
先奉上源码内容如下
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果缓存中不存在则调用wrapIfNecessary()方法创建代理
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
以上调用的是beanPostProcessor接口的postProcessAfterInitialization(Object bean,String beanName)的方法,其一般是bean对象被实例化的最后一步操作的,此处避而不谈了,我们转而查看wrapIfNecessary()的内部是如何操作的
AbstractAutoProxyCreator#wrapIfNecessary()-创建代理对象帮助函数
/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 查看缓存是否存在此bean
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// Advice/Advisor/AopInfrastructureBean接口的beanClass不进行代理以及对beanName为aop内的切面名也不进行代理,此处可查看子类复写的sholdSkip()方法
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 查找对代理类相关的advisor对象集合,此处就与ponit-cut表达式有关了
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 对相应的advisor不为空才采取代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 调用createProxy()方法创建真正的代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
对上述的源码分析作下简单的总结
首先对
Advice/Advisor/AopInfrastructureBean接口的实现类不进行代理操作;对beanName为aspectName的bean对象也不采取代理操作再而需要查找beanClass有几个advisor与之相关联,这当然与每个
Advisor接口内的PointCut对象对应的表达式expression有关。只有关联的Advisor个数不为0,才可采取代理(此处查找Advisor关联个数的源码读者可自行分析AspectJAwareAdvisorAutoProxyCreator#shouldSkip()方法)真正的代理操作是由
AbstractAutoProxyCreator#createProxy()内部方法实现
AbstractAutoProxyCreator#createProxy()-创建真正的AOP代理
对符合条件的beanClass进行相应的代理操作,简单看下源码
/**
* Create an AOP proxy for the given bean.
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @param specificInterceptors the set of interceptors that is
* specific to this bean (may be empty, but not null)
* @param targetSource the TargetSource for the proxy,
* already pre-configured to access the bean
* @return the AOP proxy for the bean
* @see #buildAdvisors
*/
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 创建AOP代理工厂,拷贝相同的属性
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 是否采用动态代理
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 查看beanClass对应的类是否含有InitializingBean.class/DisposableBean.class/Aware.class接口,无则采用静态代理,有则采用动态代理
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 获得所有关联的Advisor集合
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
// 此处的targetSource一般为SingletonTargetSource
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
// 是否设置预过滤模式,此处针对本文为true
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
对以上的源码也作下简单的总结
采用ProxyFactory对象来创建代理对象
如果AOP没有指定proxyTargetClass属性,则针对beanClass含有非
InitializingBean/DisposableBean/Aware接口的bean采用静态代理,反之采用动态代理ProxyFactory创建代理对象前也需要设置与beanClass相关联的advisor集合
ProxyFactory#getProxy()-最终创建代理类
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
以上的源码我们只需要关注createAopProxy()方法即可,此处我们直接查看DefaultAopProxyFactory#createAopProxy()源码,参考如下
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
上述源码很简单,默认是采用JDK静态代理,对beanClass为非接口实现类采取CGLIB动态代理
小结
循序渐进的分析的总结见以上的各部分小结,我们只需要知道AOP代理的beanClass必须有相应的
Advisor接口与之绑定,才会创建AOP代理创建的代理类无非是JDK代理抑或是CGLIB代理,但是具体关联的
Advisor集合的处理逻辑见下文讲解
SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator的更多相关文章
- SpringAop源码情操陶冶-JdkDynamicAopProxy
承接前文SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator,本文在前文的基础上稍微简单的分析默认情况下的AOP代理,即JDK静态代理 JdkDyna ...
- Spring源码情操陶冶-AOP之ConfigBeanDefinitionParser解析器
aop-Aspect Oriented Programming,面向切面编程.根据百度百科的解释,其通过预编译方式和运行期动态代理实现程序功能的一种技术.主要目的是为了程序间的解耦,常用于日志记录.事 ...
- SpringMVC源码情操陶冶-FreeMarker之web配置
前言:本文不讲解FreeMarkerView视图的相关配置,其配置基本由FreeMarkerViewResolver实现,具体可参考>>>SpringMVC源码情操陶冶-ViewRe ...
- Spring源码情操陶冶-AbstractApplicationContext#finishBeanFactoryInitialization
承接前文Spring源码情操陶冶-AbstractApplicationContext#registerListeners 约定web.xml配置的contextClass为默认值XmlWebAppl ...
- Spring源码情操陶冶-AbstractApplicationContext#registerListeners
承接前文Spring源码情操陶冶-AbstractApplicationContext#onRefresh 约定web.xml配置的contextClass为默认值XmlWebApplicationC ...
- Spring源码情操陶冶-AbstractApplicationContext#onRefresh
承接前文Spring源码情操陶冶-AbstractApplicationContext#initApplicationEventMulticaster 约定web.xml配置的contextClass ...
- Spring源码情操陶冶-AbstractApplicationContext#initApplicationEventMulticaster
承接前文Spring源码情操陶冶-AbstractApplicationContext#initMessageSource 约定web.xml配置的contextClass为默认值XmlWebAppl ...
- Spring源码情操陶冶-AbstractApplicationContext#initMessageSource
承接前文Spring源码情操陶冶-AbstractApplicationContext#registerBeanPostProcessors 约定web.xml配置的contextClass为默认值X ...
- Spring源码情操陶冶-AbstractApplicationContext#registerBeanPostProcessors
承接前文Spring源码情操陶冶-AbstractApplicationContext#invokeBeanFactoryPostProcessors 瞧瞧官方注释 /** * Instantiate ...
随机推荐
- TETeLasr Cutting System 开机回零问题
TETeLasr Cutting System 开机回零问题 :打开 "轴信息" :打开 加工参数-->机器参数-->脉冲当量: X轴==4000 Y轴== ...
- 浅析前端开发中的 MVC/MVP/MVVM 模式
MVC,MVP和MVVM都是常见的软件架构设计模式(Architectural Pattern),它通过分离关注点来改进代码的组织方式.不同于设计模式(Design Pattern),只是为了解决一类 ...
- hdu3756三分基础题
Dome of Circus Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 【bzoj2761】[JLOI2011]不重复数字
给出N个数,要求把其中重复的去掉,只保留第一次出现的数. 例如,给出的数为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 18 3 19 6 5 4. Inpu ...
- bzoj1143 祭祀river(最大独立集)
[CTSC2008]祭祀river Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2175 Solved: 1098[Submit][Status] ...
- OpenVPN server端配置文件详细说明(转)
本文将介绍如何配置OpenVPN服务器端的配置文件.在Windows系统中,该配置文件一般叫做server.ovpn:在Linux/BSD系统中,该配置文件一般叫做server.conf.虽然配置文件 ...
- js 防止变量冲突
解决方法 sc1 和sc2 的a都是window.a 会指向一个变量 1:使用匿名函数将脚本包起来,全局变量用来通信 如window.x; 2:命名空间 代码: <script> (fun ...
- asp.net或者MVC定时自动执行某操作
using System; using System.IO; using System.Runtime.CompilerServices; using System.Text; namespace S ...
- 一步使你的asp.net网站在手机浏览器上全屏显示
首先要加入下面的代码: <meta name="viewport" content="width=device-width, initial-scale=1.0, ...
- SAP 参照sto订单创建外向交货BAPI
DATA: SHIP_POINT TYPE TVST-VSTEL, "装运点/接收点 NUM_DELIVERIES TYPE VBNUM, STOCK_TRANS_ITEMS WITH HE ...