AOP代理对象的创建

AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现:

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) { // 查找实现了InstantiationAwareBeanPostProcessor接口的BeanPostProcessor
// 其中在spring-aop模块定义的AspectJAwareAdvisorAutoProxyCreator就实现了InstantiationAwareBeanPostProcessor接口
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // 调用postProcessBeforeInstantiation方法创建对象result
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); // 如果创建成功则直接返回
if (result != null) {
return result;
}
}
}
return null;
}
核心实现为:获取所有的BeanPostProcessor,然后遍历查看是否为子接口InstantiationAwareBeanPostProcessor,如果是则调用其postProcessBeforeInstantiation方法。
AOP代理对象创建器:AspectJAwareAdvisorAutoProxyCreator
InstantiationAwareBeanPostProcessor接口是BeanPostProcessor接口的子接口,主要作用如下英文所示:即主要用于为特殊定制目标bean的实例化过程,如给目标对象创建代理对象。
Typically used to suppress default instantiation for specific target beans,
for example to create proxies with special TargetSources (pooling targets,
lazily initializing targets, etc), or to implement additional injection strategies
such as field injection. This interface is a special purpose interface, mainly for internal use within the framework
在spring-aop的配置解析的分析可知:Spring AOP源码分析(二):AOP的三种配置方式与内部解析实现
,在解析spring的XML配置文件applicationContext.xml的aop:config或aop:aspect-autoproxy标签时,会创建并注册AspectJAwareAdvisorAutoProxyCreator(aop:aspect-autoproxy对应的AnnotationAwareAspectJAutoProxyCreator为AspectJAwareAdvisorAutoProxyCreator子类)这个BeanPostProcessor到spring容器。
AspectJAwareAdvisorAutoProxyCreator的类继承体系结构中,实现了InstantiationAwareBeanPostProcessor接口,具体为在抽象父类AbstractAutoProxyCreator:同时定义了postProcessBeforeInstantiation方法的实现。
// 提供为给定的bean对象创建对应的代理对象的方法实现
// 同时提供代理对象需要的方法拦截器的创建,其中拦截器包括所有代理对象公用的拦截器和某个代理对象私有的拦截器
@SuppressWarnings("serial")
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { ... // 在bean对象实例的创建过程中,在创建bean对象实例之前,先调用这个方法,看是否需要创建一个AOP代理对象直接返回
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName); // 返回null,则表示不是AOP的目标对象,不需要创建代理对象
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
} // Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
} // specificInterceptors类型为Advisor[],是当前bean需要的辅助功能列表
// 因为Advisor集成了pointcut和advice,故可以知道当前bean是否在pointcut拦截范围内,
// 如果在获取配置对应的advice列表,该列表作为代理对象的interceptor方法拦截器
// getAdvicesAndAdvisorsForBean由子类实现
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); // 基于以上辅助功能列表,创建该bean对应的代理对象proxy
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass()); // 只有创建了proxy,才不返回null
return proxy;
} return null;
} ... }
postProcessBeforeInstantiation方法的核心逻辑为:通过在spring-aop配置解析时创建的advisors来为该目标bean查找对应的辅助方法advices,其中advisor为集成了pointcut和advice。这些辅助方法advices作为代理对象的方法拦截器列表specificInterceptors,即代理对象拦截目标对象的方法执行,然后在方法执行前后可以执行该方法拦截器列表对应的方法,从而为目标对象的方法添加这些辅助功能。
创建代理对象:createProxy
createProxy的定义如下:代理对象可以基于JDK的动态代理或者基于CGLIB来创建,其中默认为基于JDK的动态代理,如果aop:config的proxy-target-class属性为true或者目标类没有实现接口,则使用CGLIB来创建代理对象。
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
} // 每个bean对象都使用一个单例的ProxyFactory来创建代理对象,因为每个bean需要的辅助方法不一样,
// 然后将该ProxyFactory对象引用作为构造函数参数创建对应的代理对象
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this); // 检查是否配置了<aop:config />节点的proxy-target-class属性为true
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
} Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); // 为该代理工厂添加辅助功能包装器Advisors,结合Advisors来生成代理对象的方法拦截器
proxyFactory.addAdvisors(advisors); // 目标类
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
} // 为目标类创建代理对象,如果配置了aop:config的proxy-target-class为true,则使用CGLIB
// 否则如果目标类为接口则使用JDK代理,否则使用CGLIB
return proxyFactory.getProxy(getProxyClassLoader());
}
JDK动态代理
基于接口实现,通过实现目标类所包含的接口的方法来实现代理,即返回的代理对象为接口的实现类。由于是基于JDK的动态代理实现,即实现了JDK提供的InvocationHandler接口,故在运行时在invoke方法拦截目标类对应被代理的接口的所有方法的执行:获取当前执行的方法对应的方法拦截器链,然后通过反射执行该方法时,在方法执行前后执行对应的方法拦截器。
// JDK的动态代理是基于接口的,故只能代理接口中定义的方法。
// 该类需要通过代理工厂,具体为继承了AdvisedSupport的代理工厂来创建,而不是直接创建,
// 因为AdvisedSupport提供了AOP的相关配置信息,如Advisors列表等。
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { ... public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource;
Object target = null; try { ... Object retVal; if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
} // Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null); // 获取该方法对应的方法拦截器列表
// 实现:通过该方法所在类对应的Advisors,获取该方法的辅助功能Advices列表,即方法拦截器列表。这里的实现为懒加载,
// 即当方法第一次调用的时候才创建该方法拦截器列表,然后使用一个ConcurrentHashMap缓存起来,之后的方法调用直接使用。 // 其中advised就是该方法的所在bean对应的ProxyFactory对象引用,通过ProxyFactory来创建AopProxy,即当前类对象实例。 // Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation. // 当前执行的方法不包括方法拦截器,即不需要额外的辅助功能,则可以直接执行
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 如果当前方法包括方法拦截器,即在执行时需要其他额外的辅助功能,则创建ReflectiveMethodInvocation
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
} // Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
...
} ... }
CGLIB代理
  • 创建目标类的子类来实现代理,代理拦截的只能是目标类的public和protected方法。核心方法为getProxy即创建代理对象,在这里织入了辅助功能。

// 基于类的代理,具体实现为通过创建目标类的子类来实现代理,即代理对象对应的类为目标类的子类。
// 所以目标类的需要被代理的方法不能为final,因为子类无法重写final的方法;同时被代理的方法需要是public或者protected,不能是static,private或者包可见,即不加可见修饰符。
// 如在事务中,@Transactional注解不能对private,static,final,包可见的方法添加事务功能,只能为public方法。
// 这个代理对象也需要通过代理工厂来创建,具体为继承了AdvisedSupport的代理工厂来创建,而不是直接创建。
@SuppressWarnings("serial")
class CglibAopProxy implements AopProxy, Serializable { ... // 创建代理对象
public Object getProxy(@Nullable ClassLoader classLoader) { ... Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
} // Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader); // 创建目标类的子类来实现代理,即织入辅助功能
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types); // 创建代理对象
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
} ... } ... }

获取更多学习资料,可以加群:473984645或扫描下方二维码

Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理的更多相关文章

  1. 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  2. Spring -- <tx:annotation-driven>注解基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)的区别。

    借鉴:http://jinnianshilongnian.iteye.com/blog/1508018 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional ...

  3. 5.2 spring5源码--spring AOP源码分析三---切面源码分析

    一. AOP切面源码分析 源码分析分为三部分 1. 解析切面 2. 创建动态代理 3. 调用 源码的入口 源码分析的入口, 从注解开始: 组件的入口是一个注解, 比如启用AOP的注解@EnableAs ...

  4. Spring AOP源码分析(二)动态A0P自定义标签

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 之前讲过Spring中的自定义注解,如果声明了自定义的注解,那么就一定 ...

  5. Spring <tx:annotation-driven>注解 JDK动态代理和CGLIB动态代理 区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  6. Spring AOP源码分析(三)创建AOP代理

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.获取增强器 1. 普通增强器的获取 2. 增加同步实例化增强 ...

  7. spring AOP源码分析(三)

    在上一篇文章 spring AOP源码分析(二)中,我们已经知道如何生成一个代理对象了,那么当代理对象调用代理方法时,增强行为也就是拦截器是如何发挥作用的呢?接下来我们将介绍JDK动态代理和cglib ...

  8. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  9. 5.2 Spring5源码--Spring AOP源码分析二

    目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...

随机推荐

  1. WebBug靶场介绍篇 — 01

    今天是星期天,干点啥,反正一天没事,我也不想继续去搞 msf 的那些什么浏览器提权啊,PDF 提权啊,快捷方式提取啊,或者木马免杀什么的,毕竟现在我也不是为了去找工作而去学那些工具了,,, 说开这个靶 ...

  2. 红黑数之原理分析及C语言实现

    目录: 1.红黑树简介(概念,特征,用途) 2.红黑树的C语言实现(树形结构,添加,旋转) 3.部分面试题() 1.红黑树简介 1.1 红黑树概念 红黑树(Red-Black Tree,简称R-B T ...

  3. scrapy主要防止封IP策略

    scrapy如果抓取太频繁了,就被被封IP,目前有以下主要策略保证不会被封: 策略1:设置download_delay下载延迟,数字设置为5秒,越大越安全 策略2:禁止Cookie,某些网站会通过Co ...

  4. Mentor_丝印检查——手工绘制丝印线条(标注)到丝印位号距离的检查

    http://www.eda365.com/thread-193942-1-1.html 在此之前丝印的检查基本是停留在丝印与阻焊的距离检查,而器件丝印框和手工绘制的线条与器件位号的检查都不到位,据我 ...

  5. vim与ctags/cscope的完美结合

    1. 安装vim/ctags/cscope ctag 2. 在源码根目录下执行 sudo ctags -R .   会生成tags文件,里面包含着整个源码目录下的符号信息. 3. 直接到达某个符号(比 ...

  6. eduCF#61 F. Clear the String /// 区间DP 消除连续一段相同字符 全部消完的最少次数

    题目大意: 给定字符串 每次消除可消除连续的一段相同的字符的子串 求消除整个字符串的最少消除次数 #include <bits/stdc++.h> using namespace std; ...

  7. hdu 6435 /// 状压

    题目大意: 给定 n m k 为 n种主武器 m种副武器 武器有k种属性 接下来n行 先给定当前主武器的综合分s1 再给定k种属性的值 接下来m行 先给定当前副武器的综合分s2 再给定k种属性的值 要 ...

  8. C# 基于创建一个mysql 连接池

    创建一个连接池操作类 using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using Syste ...

  9. C语言typedef

    #include <stdio.h> //基本类型 typedef int MyInt; //可以对typedef产生的类型名二次起别名 typedef MyInt MyInt2; // ...

  10. 从零开始搭建系统2.2——ELK安装及配置

    ELK 最新版本对JDK的最低要求是1.8,安装java_1.8版本 一.Elasticsearch 1.创建目录 2.下载安装包 wget https://artifacts.elastic.co/ ...