Spring AOP的代理对象是如何创建的

您所在的位置:网站首页 spring动态创建对象 Spring AOP的代理对象是如何创建的

Spring AOP的代理对象是如何创建的

2024-07-06 11:35| 来源: 网络整理| 查看: 265

前言

原文:链接: 【小家Spring】详解Spring AOP的底层代理JdkDynamicAopProxy和ObjenesisCglibAopProxy的源码分析(介绍CGLIB使用中的坑)

在前面的博文我们了解到,Spring所有的代理AopProxy的创建最后都是ProxyCreatorSupport#createAopProxy这个方法,而这个方法如下:

public class ProxyCreatorSupport extends AdvisedSupport { //其唯一实现为DefaultAopProxyFactory private AopProxyFactory aopProxyFactory; protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); } }

显然它又是调用了AopProxyFactory#createAopProxy方法,它的唯一实现为DefaultAopProxyFactory。

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @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); } } private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { Class[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]))); } }

它做了一个简单的逻辑判断:若类实现接口,使用JdkDynamicAopProxy最终去创建,否则交给ObjenesisCglibAopProxy。

最终拿到AopProxy后,调用AopProxy#getProxy()就会拿到这个代理对象,从而进行相应的工作了。

我们基本有一共共识就是:默认情况下,若我们实现了接口,就实用JDK动态代理,若没有就实用CGLIB。那么就下来,就具体看看关乎到代理对象的创建、执行的一个具体过程原理

AopProxy就是Spring 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 // 我们发现它自己就实现了了InvocationHandler,所以处理器就是它自己。会实现invoke方法 // 它还是个final类 默认是包的访问权限 final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class); /** 这里就保存这个AOP代理所有的配置信息 包括所有的增强器等等 */ private final AdvisedSupport advised; // 标记equals方法和hashCode方法是否定义在了接口上===== private boolean equalsDefined; private boolean hashCodeDefined; public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { Assert.notNull(config, "AdvisedSupport must not be null"); // 内部再校验一次:必须有至少一个增强器 和 目标实例才行 if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { throw new AopConfigException("No advisors and no TargetSource specified"); } this.advised = config; } @Override public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); } // 真正创建JDK动态代理实例的地方 @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } // 这部很重要,就是去找接口 我们看到最终代理的接口就是这里返回的所有接口们(除了我们自己的接口,还有Spring默认的一些接口) 大致过程如下: //1、获取目标对象自己实现的接口们(最终肯定都会被代理的) //2、是否添加`SpringProxy`这个接口:目标对象实现对就不添加了,没实现过就添加true //3、是否新增`Adviced`接口,注意不是Advice通知接口。 实现过就不实现了,没实现过并且advised.isOpaque()=false就添加(默认是会添加的) //4、是否新增DecoratingProxy接口。传入的参数decoratingProxy为true,并且没实现过就添加(显然这里,首次进来是会添加的) //5、代理类的接口一共是目标对象的接口+上面三个接口SpringProxy、Advised、DecoratingProxy(SpringProxy是个标记接口而已,其余的接口都有对应的方法的) //DecoratingProxy 这个接口Spring4.3后才提供 Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 第三个参数传的this,处理器就是自己嘛 到此一个代理对象就此new出来啦 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } // 找找看看接口里有没有自己定义equals方法和hashCode方法,这个很重要 然后标记一下 // 注意此处用的是getDeclaredMethods,只会找自己的 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; } } } } // 对于这部分代码和采用CGLIB的大部分逻辑都是一样的,Spring对此的解释很有意思: // 本来是可以抽取出来的,使得代码看起来更优雅。但是因为此会带来10%得性能损耗,所以Spring最终采用了粘贴复制的方式各用一份 // Spring说它提供了基础的套件,来保证两个的执行行为是一致的。 //proxy:指的是我们所代理的那个真实的对象;method:指的是我们所代理的那个真实对象的某个方法的Method对象args:指的是调用那个真实对象方法的参数。 // 此处重点分析一下此方法,这样在CGLIB的时候,就可以一带而过了~~~因为大致逻辑是一样的 @Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 它是org.aopalliance.intercept这个包下的 AOP联盟得标准接口 MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; // 进入invoke方法后,最终操作的是targetSource对象 // 因为InvocationHandler持久的就是targetSource,最终通过getTarget拿到目标对象 TargetSource targetSource = this.advised.targetSource; Object target = null; try { //“通常情况”Spring AOP不会对equals、hashCode方法进行拦截增强,所以此处做了处理 // equalsDefined为false(表示自己没有定义过eequals方法) 那就交给代理去比较 // hashCode同理,只要你自己没有实现过此方法,那就交给代理吧 // 需要注意的是:这里统一指的是,如果接口上有此方法,但是你自己并没有实现equals和hashCode方法,那就走AOP这里的实现 // 如国接口上没有定义此方法,只是实现类里自己@Override了HashCode,那是无效的,就是普通执行吧 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { return hashCode(); } // 下面两段做了很有意思的处理:DecoratingProxy的方法和Advised接口的方法 都是是最终调用了config,也就是this.advised去执行的~~~~ else if (method.getDeclaringClass() == DecoratingProxy.class) { // There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised); } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } // 这个是最终该方法的返回值~~~~ Object retVal; //是否暴露代理对象,默认false可配置为true,如果暴露就意味着允许在线程内共享代理对象, //注意这是在线程内,也就是说同一线程的任意地方都能通过AopContext获取该代理对象,这应该算是比较高级一点的用法了。 // 这里缓存一份代理对象在oldProxy里~~~后面有用 if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } //通过目标源获取目标对象 (此处Spring建议获取目标对象靠后获取 而不是放在上面) target = targetSource.getTarget(); Class targetClass = (target != null ? target.getClass() : null); // 获取作用在这个方法上的所有拦截器链~~~ 参见DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice方法 // 会根据切点表达式去匹配这个方法。因此其实每个方法都会进入这里,只是有很多方法得chain事Empty而已 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { // 若拦截器为空,那就直接调用目标方法了 // 对参数进行适配:主要处理一些数组类型的参数,看是表示一个参数 还是表示多个参数(可变参数最终到此都是数组类型,所以最好是需要一次适配) Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); // 这句代码的意思是直接调用目标方法~~~ retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // 创建一个invocation ,此处为ReflectiveMethodInvocation 最终是通过它,去执行前置加强、后置加强等等逻辑 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // 此处会执行所有的拦截器链 交给AOP联盟的MethodInvocation去处理。当然实现还是我们Spring得ReflectiveMethodInvocation retVal = invocation.proceed(); } // 获取返回值的类型 Class returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // 一些列的判断条件,如果返回值不为空,且为目标对象的话,就直接将目标对象赋值给retVal retVal = proxy; } // 返回null,并且还不是Void类型。。。抛错 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()) { targetSource.releaseTarget(target); } // 把老的代理对象重新set进去~~~ if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } } // AOP帮我们实现的CgLib方法 @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); } // AOP帮我们实现的HashCode方法 @Override public int hashCode() { return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode(); } } 二、CglibAopProxy class CglibAopProxy implements AopProxy, Serializable { // 它的两个getProxy()相对来说比较简单,就是使用CGLIB的方式,利用Enhancer创建了一个增强的实例 // 这里面比较复杂的地方在:getCallbacks()这步是比较繁琐的 // setCallbackFilter就是看看哪些方法需要拦截、哪些不需要~~~~ @Override public Object getProxy() { return getProxy(null); } // CGLIB重写的这两个方法 @Override public boolean equals(Object other) { return (this == other || (other instanceof CglibAopProxy && AopProxyUtils.equalsInProxy(this.advised, ((CglibAopProxy) other).advised))); } @Override public int hashCode() { return CglibAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode(); } // 最后,所有的被代理得类的所有的方法调用,都会进入DynamicAdvisedInterceptor#intercept这个方法里面来(相当于JDK动态代理得invoke方法) // 它实现了MethodInterceptor接口 private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable { private final AdvisedSupport advised; public DynamicAdvisedInterceptor(AdvisedSupport advised) { this.advised = advised; } @Override @Nullable public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; // 目标对象源 TargetSource targetSource = this.advised.getTargetSource(); try { if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // 拿到目标对象 这里就是使用targetSource的意义,它提供多个实现类,从而实现了更多的可能性 // 比如:SingletonTargetSource HotSwappableTargetSource PrototypeTargetSource ThreadLocalTargetSource等等 target = targetSource.getTarget(); Class targetClass = (target != null ? target.getClass() : null); // 一样的,也是拿到和这个方法匹配的 所有的增强器、通知们 和JDK Proxy中是一样的 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // 没有增强器,同时该方法是public得 就直接调用目标方法(不拦截) if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { // CglibMethodInvocation这里采用的是CglibMethodInvocation,它是`ReflectiveMethodInvocation`的子类 到这里就和JDK Proxy保持一致勒 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } } @Override public boolean equals(Object other) { return (this == other || (other instanceof DynamicAdvisedInterceptor && this.advised.equals(((DynamicAdvisedInterceptor) other).advised))); } /** * CGLIB uses this to drive proxy creation. */ @Override public int hashCode() { return this.advised.hashCode(); } } } 三、ObjenesisCglibAopProxy

ObjenesisCglibAopProxy继承自CglibAopProxy,它只重写了createProxyClassAndInstance方法

// 它是Spring4.0之后提供的 class ObjenesisCglibAopProxy extends CglibAopProxy { // SpringObjenesis是Spring对Objenesis接口的一个实现 private static final SpringObjenesis objenesis = new SpringObjenesis(); public ObjenesisCglibAopProxy(AdvisedSupport config) { super(config); } // 创建一个代理得实例 @Override protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { Class proxyClass = enhancer.createClass(); Object proxyInstance = null; // 如果为true,那我们就采用objenesis去new一个实例~~~ if (objenesis.isWorthTrying()) { try { proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache()); } catch (Throwable ex) { logger.debug("Unable to instantiate proxy using Objenesis, " + "falling back to regular proxy construction", ex); } } // 若果还为null,就再去拿到构造函数(指定参数的) if (proxyInstance == null) { // Regular instantiation via default constructor... try { Constructor ctor = (this.constructorArgs != null ? proxyClass.getDeclaredConstructor(this.constructorArgTypes) : proxyClass.getDeclaredConstructor()); // 通过此构造函数 去new一个实例 ReflectionUtils.makeAccessible(ctor); proxyInstance = (this.constructorArgs != null ? ctor.newInstance(this.constructorArgs) : ctor.newInstance()); } catch (Throwable ex) { throw new AopConfigException("Unable to instantiate proxy using Objenesis, " + "and regular proxy instantiation via default constructor fails as well", ex); } } ((Factory) proxyInstance).setCallbacks(callbacks); return proxyInstance; } } 3.1 Objenesis:另一种实例化对象的方式

它专门用来创建对象,即使你没有空的构造函数,都木有问题~~ 可谓非常的强大 它不使用构造方法创建Java对象,所以即使你有空的构造方法,也是不会执行的。

Objenesis是一个Java的库,主要用来创建特定的对象。由于不是所有的类都有无参构造器又或者类构造器是private,在这样的情况下,如果我们还想实例化对象,class.newInstance是无法满足的。

public class MainTest { public static void main(String[] args) throws Exception { Objenesis objenesis = new ObjenesisStd(); // 它竟然创建成功了 MyDemo myDemo = objenesis.newInstance(MyDemo.class); System.out.println(myDemo); //com.fsx.maintest.MyDemo@1f32e575 System.out.println(myDemo.code); //null 特别注意:这里是null,而不是10 // 若直接这样创建 就报错 java.lang.InstantiationException: com.fsx.maintest.MyDemo System.out.println(MyDemo.class.newInstance()); } } class MyDemo { public String code = "10"; public MyDemo(String code) { this.code = code; } }

使用用ObjectInstantiator

public static void main(String[] args) throws Exception { Objenesis objenesis = new ObjenesisStd(); // 相当于生成了一个实例创建的工厂,接下来就可以很方便得创建实例了 // 如果你要创建多个实例,建议这么来创建 ObjectInstantiator instantiator = objenesis.getInstantiatorOf(MyDemo.class); MyDemo myDemo1 = instantiator.newInstance(); MyDemo myDemo2 = instantiator.newInstance(); System.out.println(myDemo1); System.out.println(myDemo1.code); //null System.out.println(myDemo2); }

Objenesis主要应用场景: 序列化,远程调用和持久化 -对象需要实例化并存储为到一个特殊的状态,而没有调用代码 代理,AOP库和Mock对象 -类可以被子类继承而子类不用担心父类的构造器。 容器框架 -对象可以以非标准的方式被动态实例化(比如Spring就是容器框架)。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3