Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义相关的知识,希望对你有一定的参考价值。
Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义
引子
回看生成DefaultAopProxyFactory的createAopProxy方法来生成代理类
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException
if (!NativeDetector.inNativeImage() &&
(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))
//采用JdkDynamicAopProxy生成jdk动态代理对象
return new JdkDynamicAopProxy(config);
//采用ObjenesisCglibAopProxy生成cglib动态代理对象
return new ObjenesisCglibAopProxy(config);
else
return new JdkDynamicAopProxy(config);
/**
* Determine whether the supplied @link AdvisedSupport has only the
* @link org.springframework.aop.SpringProxy interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config)
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
Spring所有的代理AopProxy的创建最后都是ProxyCreatorSupport#createAopProxy这个方法
protected final synchronized AopProxy createAopProxy()
if (!this.active)
activate();
//getAopProxyFactory拿到的就是DefaultAopProxyFactory
//createAopProxy调用的就是DefaultAopProxyFactory类里面的方法
return getAopProxyFactory().createAopProxy(this);
显然它又是调用了AopProxyFactory#createAopProxy方法,它的唯一实现为DefaultAopProxyFactory。
它做了一个简单的逻辑判断:若实现类接口,使用JdkDynamicAopProxy最终去创建,否则交给ObjenesisCglibAopProxy。
最终拿到AopProxy后,调用AopProxy#getProxy()就会拿到这个代理对象,从而进行相应的工作了。
我们基本有一共共识就是:默认情况下,若我们实现了接口,就实用JDK动态代理,若没有就实用CGLIB。那么就下来,就具体看看关乎到代理对象的创建、执行的一个具体过程原理
动态代理和静态代理回顾
AOP(Aspect Orient Programming),一般称为面向切面编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。
AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。静态代理是编译期实现,动态代理是运行期实现,可想而知前者拥有更好的性能。
静态代理:
静态代理是编译阶段生成AOP代理类,也就是说生成的字节码就织入了增强后的AOP对象;(并不会创建出多余的对象)
实现方式:
- 包装器模式:持有目标对象的引用,然后实际上是调用目标对象的方法。 这种方式也可称为代理模式,但是有明显的缺点(比如一般都需要实现同一个接口,且它是以编码的方式去实现的,侵入性高)
- AspectJ静态代理方式:非常非常强大。Aspectj并不是动态的在运行时生成代理类,而是在编译的时候就植入代码到class文件。由于是静态织入的,所以性能相对来说比较好。Aspectj不受类的特殊限制,不管方法是private、或者static、或者final的,都可以代理,Aspectj不会代理除了限定方法之外任何其他诸如toString(),clone()等方法,唯一缺点就是必须有AspectJ自己的编译器的支持,所以其实很少使用 Spring也是提供了相关类支持的,比如:LoadTimeWeaverAwareProcessor
基于AspectJ的静态代理方式非常强大,但是它依赖于它自己的编译器。并且还有自己的个性化语言,使用起来不够方便,因此其实还是使用得较少的。主要还是以动态代理为主~~~
动态代理:
动态代理则不会修改字节码,而是在内存中临时生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法
这在我们平时使用中得到了大量的使用,因为使用简单并且还非常灵活,下面就重点介绍。
AopProxy:Aop代理接口
它是一个AOP代理的抽象接口。提供了两个方法,让我们可以获取对应 配置的AOP对象的代理:
public interface AopProxy
//Create a new proxy object. Uses the AopProxy's default class loader ClassUtils.getDefaultClassLoader()
Object getProxy();
Object getProxy(@Nullable ClassLoader classLoader);
它的继承关系也很简单,就是接下来我们要说的那几个
JdkDynamicAopProxy—jdk生成动态代理对象
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = 5531744639992436476L;
/** We use a static Log to avoid serialization issues. */
private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
/**当前代理对象相关配置信息保存 **/
private final AdvisedSupport advised;
//当前代理对象需要代理的接口
private final Class<?>[] proxiedInterfaces;
/**
* Is the @link #equals method defined on the proxied interfaces?
*/
private boolean equalsDefined;
/**
* Is the @link #hashCode method defined on the proxied interfaces?
*/
private boolean hashCodeDefined;
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE)
throw new AopConfigException("No advisors and no TargetSource specified");
this.advised = config;
//completeProxiedInterfaces方法会获得当前类需要代理的接口
//并且额外还会让代理对象实现两个接口,但是因为第二个参数为true
//因此一共会让代理对象再额外实现三个接口:SpringProxy,Advised和DecoratingProxy
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
@Override
public Object getProxy()
return getProxy(ClassUtils.getDefaultClassLoader());
@Override
public Object getProxy(@Nullable ClassLoader classLoader)
if (logger.isTraceEnabled())
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
//获得代理对象的方法十分的简单,就是最原始的jdk生成动态代理的方法
//但是此时传入的拦截器方法为当前类,因为其实现了InvocationHandler接口
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
/**
* Finds any @link #equals or @link #hashCode method that may be defined
* on the supplied set of interfaces.
* @param proxiedInterfaces the interfaces to introspect
*/
private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces)
for (Class<?> proxiedInterface : proxiedInterfaces)
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods)
if (AopUtils.isEqualsMethod(method))
this.equalsDefined = true;
if (AopUtils.isHashCodeMethod(method))
this.hashCodeDefined = true;
if (this.equalsDefined && this.hashCodeDefined)
return;
/**
调用链的执行
*/
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Object oldProxy = null;
boolean setProxyContext = false;
//拿到包装了目标对象的TargetSource
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try
//“通常情况”Spring AOP不会对equals、hashCode方法进行拦截增强,所以此处做了处理
// equalsDefined为false(表示自己没有定义过equals方法) 那就交给代理去比较
// hashCode同理,只要你自己没有实现过此方法,那就交给代理吧
// 需要注意的是:这里统一指的是,如果接口上有此方法,但是你自己并没有实现equals和hashCode方法,那就走AOP这里的实现
// 如国接口上没有定义此方法,只是实现类里自己@Override了HashCode,那是无效的,就是普通执行吧
if (!this.equalsDefined && AopUtils.isEqualsMethod(method))
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method))
// The target does not implement the hashCode() method itself.
return hashCode();
//如果当前方法属于DecoratingProxy接口中getDecoratedClass方法
else if (method.getDeclaringClass() == DecoratingProxy.class)
// There is only getDecoratedClass() declared -> dispatch to proxy config.
//那么直接通过分析代理配置信息返回目标对象的类型
return AopProxyUtils.ultimateTargetClass(this.advised);
//opaque默认为false,表示代理对象会继承Advised接口
else if (!this.advised.opaque &&
//当前方法属于某个接口中的方法
method.getDeclaringClass().isInterface() &&
//当前接口是Advised或者其子类
method.getDeclaringClass().isAssignableFrom(Advised.class))
// Service invocations on ProxyConfig with the proxy config...
//那么当前用户是想将代理对象强制转换为advised接口后,调用该接口中某个方法
//那么这里转而调用内部维护的代理类配置信息的method方法
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
Object retVal;
//是否暴露代理对象,默认false可配置为true,如果暴露就意味着允许在线程内共享代理对象,
//注意这是在线程内,也就是说同一线程的任意地方都能通过AopContext获取该代理对象,这应该算是比较高级一点的用法了。
// 这里缓存一份代理对象在oldProxy里~~~后面有用
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);
// Get the interception chain for this method.
//对代理类配置信息中的Advisors集合进行筛选,找出可以应用到当前类和当前类的method方法上的增强器
//然后把这些增强器适配为methodInterceptor后加入集合中统一返回
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
//当前方法有相关联的拦截器链集合
// We need to create a method invocation...
//构造拦截器链
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
//拦截器链开始执行
//ReflectiveMethodInvocation的proceed方法,不清楚的可以翻看我之前的文章
//该方法最后返回方法的执行结果
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;
//如果方法实际返回值不为null,但是获得的返回结果为null,那么抛出异常
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;
finally
if (target != null && !targetSource.isStatic())
// Must have come from TargetSource.
//使用targetSource绑定的target对象,这样一来,targetSource可以完成重用111
targetSource.releaseTarget(target);
if (setProxyContext)
// 把老的代理对象重新set进去~~~
AopContext.setCurrentProxy(oldProxy);
/**
* Equality means interfaces, advisors and TargetSource are equal.
* <p>The compared object may be a JdkDynamicAopProxy instance itself
* or a dynamic proxy wrapping a JdkDynamicAopProxy instance.
*/
@Override
public boolean equals(@Nullable Object other)
if (other == this)
return true;
if (other == null)
return false;
JdkDynamicAopProxy otherProxy;
if (other instanceof JdkDynamicAopProxy)
otherProxy = (JdkDynamicAopProxy) other;
else if (Proxy.isProxyClass(other.getClass()))
InvocationHandler ih = Proxy.getInvocationHandler(other);
if (!(ih instanceof JdkDynamicAopProxy))
return false;
otherProxy = (JdkDynamicAopProxy) ih;
else
// Not a valid comparison...
return false;
// If we get here, otherProxy is the other AopProxy.
return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised);
/**
* Proxy uses the hash code of the TargetSource.
*/
@Override
public int hashCode()
return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
该类的设计思路和我们平时自己使用jdk动态代理思路一致,大致有以下几步:
- 通过构造函数传入的AdvisedSupport代理配置信息,分析得到当前代理类需要实现的接口数组
- 获取代理对象的时候,就和平时一样,通过newProxyInstance完成即可,但是InvocationHandler传入的是JdkDynamicAopProxy自身,因为他实现了该接口
- 当目标方法被调用,会触发InvocationHandler的invoke方法,在该方法内JdkDynamicAopProxy会首先获取拦截器链,然后执行拦截器链,获取最终执行结果,然后返回
还有一点需要注意,就是代理类会额外实现SpringProxy,Advised和DecoratingProxy三个接口,代码体现在下面这行:
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
CglibAopProxy----cglib生成动态代理对象
要想搞懂CglibAopProxy的组织思路,callbackFilter必须要了解,建议大家先看一下:
@SuppressWarnings("serial")
class CglibAopProxy implements AopProxy, Serializable
// Constants for CGLIB callback array indices
//这里的序号用于callBackFilter中,选择某个方法交给某个callback时,会用到
private static final int AOP_PROXY = 0;
private static final int INVOKE_TARGET = 1;
private static final int NO_OVERRIDE = 2;
private static final int DISPATCH_TARGET = 3;
private static final int DISPATCH_ADVISED = 4;
private static final int INVOKE_EQUALS = 5;
private static final int INVOKE_HASHCODE = 6;
/** Logger available to subclasses; static to optimize serialization. */
protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);
/** Keeps track of the Classes that we have validated for final methods. */
//对已经校验过的类进行缓存处理
private static final Map<Class<?>, Boolean> validatedClasses = new WeakHashMap<>();
/** 代理配置类信息 **/
protected final AdvisedSupport advised;
//因为是采用继承方式实现的代理,因此需要考虑父类的构造函数
@Nullable
protected Object[] constructorArgs;
//构造函数参类型
@Nullable
protected Class以上是关于Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义的主要内容,如果未能解决你的问题,请参考以下文章
Spring读源码系列之AOP--02---aop基本概念扫盲---下
Spring读源码系列之AOP--03---aop底层基础类学习
Spring读源码系列之AOP--08--aop执行完整源码流程之自动代理创建器导入的两种方式
Spring读源码系列之AOP--05---aop常用工具类学习
Spring读源码系列之AOP--07---aop自动代理创建器(拿下AOP的最后一击)
Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义