Spring AOP源码分析篇四:JDK动态代理(JdkDynamicAopProxy)和CGLIB代理(ObjenesisCglibAopProxy)

目录

1. 前文回顾

2. 常识

3. 静态代理

4. 动态代理

4.1. JDK动态代理

4.1.1. 实现方式一

4.1.2. 实现方式二

4.1.3. 反编译

4.1.4. Proxy类

4.2. CGLIB代理

5. Aoproxy

5.1. JdkDynamicAopProxy

5.2. ObjenesisCglibAopProxy

5.3. CglibAopProxy

5.3.1. Objenesis

6. 总结

7. 参考文献


1. 前文回顾

在前面文章

Spring AOP源码分析篇二:AnnotationAwareAspectJAutoProxyCreator解析并获取advisor、切点pointcut_程序源仔的博客-CSDN博客的最后,讲到了创建动态代理有两种方式,JDK反射机制提供的动态代理CGlib动态代理,这篇文章重要讲述一下这两种代理的区别。

回顾一下这个图,从里面知道了jdkDynamicProxyCglibAopProxy这两个重要的类,在默认情况下,我们用的是jdk代理方式.

2. 常识

AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。静态代理是编译期实现,动态代理是运行期实现,因为在动态运行,所以性能相比静态代理差点

3. 静态代理

静态代理在编译阶段就生成了AOP代理类,也就是说生成的class字节码就织入了增强后的aop对象。

实现方式:

1、包装器模式:这个经常被用来做demo演示,需要跟被代理对象实现同一个接口,生成一个代理对象,该代理对象持有目标对象的引用,相当于包装了一层而已,该方式侵入性高,代码冗余度高

2、AspectJ静态代理方式,不是动态的运行时生成代理类,而是在编译时植入代码到class文件中。必须依赖于AspectJ自己的编译器的支持,所以很少使用。AspectJ不受类的特殊限制,方法是private、static、final都可以代理,不过他不会代理除了限定方法之外其他任何诸如roString()、clone()等方法。

4. 动态代理

动态代理则不会修改字节码,而是在内存中临时生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法

4.1. JDK动态代理

准备一个接口和实现类

public interface Game {

    void playGame();

}

class GameImpl implements Game{

    @Override
    public void playGame(){
        System.out.println("play game");
    }
}

准备一个InvocationHandler

public class MyInvocationHandler implements InvocationHandler {

    private Object target;

    public MyInvocationHandler(Object target){
        this.target = target;
    }

    @Override
    public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable {
        System.out.println("method :" + method.getName() + " is invoked!");
        return method.invoke( target,args );
    }

    
}

4.1.1. 实现方式一

public static void main( String[] args ) {
        Game game = (Game)Proxy.newProxyInstance(
            MyInvocationHandler.class.getClassLoader(),
            new Class<?>[]{Game.class},
            new MyInvocationHandler( new GameImpl() )
        );
        game.playGame();
    }

输出:
method :playGame is invoked!
play game

这种方式最常用,里面也是最出名的三大参数

展示一下jdk动态代理图

从图中可看到,invovationHandler用于做逻辑增强目标方法调用

4.1.2. 实现方式二

public static void main( String[] args ) throws Exception{

    //实现方式二
    // 三个步骤:
    // 1、生成代理接口的Class() class com.sun.proxy.$Proxy0
    // 2、拿到构造器:public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
    // 3、new一个InvocationHandler实例~~~
    Class<?> proxyClass = Proxy.getProxyClass( MyInvocationHandler.class.getClassLoader(), Game.class );
    Constructor<?> constructor = proxyClass.getConstructor( InvocationHandler.class );
    InvocationHandler handler = new MyInvocationHandler( new GameImpl() );
    Game game = (Game)constructor.newInstance( handler );
    game.playGame();
}

输出:
method :playGame is invoked!
play game

方式二是方式一的底层原理

4.1.3. 反编译

反编译看一下代理类

// 1、所有JDK动态代理  都是Proxy的子类  而且是final修饰
// 2、实现了你所需要代理的接口
// 3、我们发现不管调用哪个方法,最终都是交给了InvocationHandler.invoke()方法  这也就是为什么需要我们提供这个接口的实现类的原因吧
public final class $Proxy0 extends Proxy implements Game {

    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    // 通过反射给Method赋值   这里我们得出结论
    // Object的三个方法equals/toString/hashCode最终都是会被代理的
    // m3是我们Game自己的业务方法
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.proxy.Game").getMethod("playGame");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }

    // 构造函数  
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void playGame() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
}

从上面代码可知:

所有具体的代理方法,逻辑都是一样的,都是调用我们前面定义好的invocationHandlerinvoke方法,从而触发目标对象对应的方法。

这里抛个问题:

jdk动态代理为什么只支持接口代理?

因为 他要继承Proxy类,java是单继承,所以jdk动态代理就只能代理接口了

4.1.4. Proxy类

在上面可以看到继承了Proxy类,那我们点进去看下

public class Proxy implements java.io.Serializable {
    
    //KeyFactory和ProxyClassFactory都是内部类
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    // 我们自己实现的执行器
    protected InvocationHandler h;

    // 我们不能直接new它的对象
    // 它里面所有的方法都是静态方法
    private Proxy() {
    }
    
    // 这个构造函数由子类调用
    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

    // 判断是否为Proxy的子类(也就是否为JDK动态代理生成的类)
    // 可以对比一下ClassUtils.isCglibProxyClass(object.getClass())  判断是否是CGLIB对象(其实就是看名字里是否含有 "$$"这个)
    public static boolean isProxyClass(Class<?> cl) {
        return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
    }

    // 最重要的一个方法:生成代理对象
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
    throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * 生成代理类的字节码文件
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
        	//获取代理类构造函数
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //创建代理实例
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

从上面代码可以知道,代理对象的class字节码,是在运行时动态生成的,这也是为什么我们叫做JDK动态代理的原因

我们从上面的方式一分析:进入Proxy.newProxyInstance

getProxyClass0方法是入口:需要传入类加载器interface

//此方法也是Proxy类下的方法
private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }

    // If the proxy class defined by the given loader implementing
    // the given interfaces exists, this will simply return the cached copy;
    // otherwise, it will create the proxy class via the ProxyClassFactory
    //意思是:如果代理类被指定的类加载器loader定义了,并实现了给定的接口interfaces,
    //那么就返回缓存的代理类对象,否则使用ProxyClassFactory创建代理类。
    return proxyClassCache.get(loader, interfaces);
}

看一下proxyClassCache

private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

proxyClassCache是个WeakCache类的对象,调用proxyClassCache.get(loader, interfaces); 可以得到缓存的代理类或创建代理类(没有缓存的情况)。

最后来到ProxyClassFactory的apply方法,代理类就是在这里生成的。

//这里的BiFunction<T, U, R>是个函数式接口,可以理解为用T,U两种类型做参数,得到R类型的返回值
private static final class ProxyClassFactory
       implements BiFunction<ClassLoader, Class<?>[], Class<?>>
   {
       // prefix for all proxy class names
       //所有代理类名字的前缀
       private static final String proxyClassNamePrefix = "$Proxy";
       
       // next number to use for generation of unique proxy class names
       //用于生成代理类名字的计数器
       private static final AtomicLong nextUniqueNumber = new AtomicLong();
 
       @Override
       public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
             
           Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            //验证代理接口,可不看
           for (Class<?> intf : interfaces) {
               /*
                * Verify that the class loader resolves the name of this
                * interface to the same Class object.
                */
               Class<?> interfaceClass = null;
               try {
                   interfaceClass = Class.forName(intf.getName(), false, loader);
               } catch (ClassNotFoundException e) {
               }
               if (interfaceClass != intf) {
                   throw new IllegalArgumentException(
                       intf + " is not visible from class loader");
               }
               /*
                * Verify that the Class object actually represents an
                * interface.
                */
               if (!interfaceClass.isInterface()) {
                   throw new IllegalArgumentException(
                       interfaceClass.getName() + " is not an interface");
               }
               /*
                * Verify that this interface is not a duplicate.
                */
               if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                   throw new IllegalArgumentException(
                       "repeated interface: " + interfaceClass.getName());
               }
           }
           //生成的代理类的包名 
           String proxyPkg = null;     // package to define proxy class in
           //代理类访问控制符: public ,final
           int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
 
           /*
            * Record the package of a non-public proxy interface so that the
            * proxy class will be defined in the same package.  Verify that
            * all non-public proxy interfaces are in the same package.
            */
           //验证所有非公共的接口在同一个包内;公共的就无需处理
           //生成包名和类名的逻辑,包名默认是com.sun.proxy,类名默认是$Proxy 加上一个自增的整数值
            //如果被代理类是 non-public proxy interface ,则用和被代理类接口一样的包名
           for (Class<?> intf : interfaces) {
               int flags = intf.getModifiers();
               if (!Modifier.isPublic(flags)) {
                   accessFlags = Modifier.FINAL;
                   String name = intf.getName();
                   int n = name.lastIndexOf('.');
                   String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                   if (proxyPkg == null) {
                       proxyPkg = pkg;
                   } else if (!pkg.equals(proxyPkg)) {
                       throw new IllegalArgumentException(
                           "non-public interfaces from different packages");
                   }
               }
           }
 
           if (proxyPkg == null) {
               // if no non-public proxy interfaces, use com.sun.proxy package
               proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
           }
 
           /*
            * Choose a name for the proxy class to generate.
            */
           long num = nextUniqueNumber.getAndIncrement();
           //代理类的完全限定名,如com.sun.proxy.$Proxy0.calss
           String proxyName = proxyPkg + proxyClassNamePrefix + num;
 
           /*
            * Generate the specified proxy class.
            */
           //核心部分,生成代理类的字节码
           byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
               proxyName, interfaces, accessFlags);
           try {
               //把代理类加载到JVM中,至此动态代理过程基本结束了
               return defineClass0(loader, proxyName,
                                   proxyClassFile, 0, proxyClassFile.length);
           } catch (ClassFormatError e) {
               /*
                * A ClassFormatError here means that (barring bugs in the
                * proxy class generation code) there was some other
                * invalid aspect of the arguments supplied to the proxy
                * class creation (such as virtual machine limitations
                * exceeded).
                */
               throw new IllegalArgumentException(e.toString());
           }
       }
   }

关键代码:生成二进制class数据

//生成二进制class数据流
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
    proxyName, interfaces, accessFlags);

generateClassFile():生产二进制数据流

saveGeneratedFiles这个字段就是生产proxy反编译文件的配置参数,默认是false

private final static boolean saveGeneratedFiles =
    java.security.AccessController.doPrivileged(
        new GetBooleanAction(
            "sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue();

调用native本地方法生成class对象

ProxyClassFactory

ProxyClassFactory是Proxy的一个静态内部类。它的逻辑包括了下面三步:

1、包名的创建逻辑

包名生成逻辑默认是com.sun.proxy,如果被代理类是non-public proxy interface(也就说实现的接口若不是public的,报名处理方式不太一样),则用和被代理类接口一样的包名,类名默认是$Proxy 加上一个自增的整数值

2、调用ProxyGenerator. generateProxyClass生成代理类字节码

-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 这个参数就是在该方法起到作用,如果为true则保存字节码到磁盘。代理类中,所有的代理方法逻辑都一样都是调用invocationHander的invoke方法(上面源码我们也能看出来)

3、把代理类字节码加载到JVM。

把字节码通过传入的类加载器加载到JVM中:defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);

4.2. CGLIB代理

写一个CGLib内部使用的增强器

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

// 注意:这个是org.springframework.cglib.proxy.MethodInterceptor
// 而不是org.aopalliance.intercept包下的
public class MyMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept( Object o, Method method, Object[] objects, MethodProxy methodProxy ) throws Throwable {
        // 此处千万不能调用method得invoke方法,否则会死循环的 只能使用methodProxy.invokeSuper 进行调用
        Object intercept = methodProxy.invokeSuper( o,objects );
        System.out.println("拦截器生效..");
        return intercept;
    }
}

main方法执行

import org.springframework.cglib.proxy.Enhancer;

// 此处需要说明:Enhancer实际属于CGLIB包的,也就是`net.sf.cglib.proxy.Enhancer`
// 但是Spring把这些类都拷贝到自己这来了,因此我用的Spring的Enhancer,包名为;`org.springframework.cglib.proxy.Enhancer`

public class EnhancerMain {   
    public static void main( String[] args ) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass( GameImpl.class );
        enhancer.setCallback( new MyMethodInterceptor() );

        Game game = (Game)enhancer.create();
        game.playGame();
    }

}


输出
play game
拦截器生效..

5. Aoproxy

AopProxy:aop代理接口,提供了两个方法让我们获取aop代理对象(都是动态代理)

public interface AopProxy {

    Object getProxy();
    Object getProxy(@Nullable ClassLoader classLoader);

}

继承关系,接下来就是要讲这几个

先写个demo,看一下Spring Aop环境

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.DecoratingProxy;

import java.lang.reflect.Proxy;
import java.util.Arrays;

public class ProxyFactoryMain {

    public static void main( String[] args ) {
        ProxyFactory proxyFactory = new ProxyFactory(new Hello());
        proxyFactory.addAdvice((MethodBeforeAdvice) (method, args1, target) ->
                                System.out.println("你被拦截了:方法名为:" + method.getName() + " 参数为--" + Arrays.asList(args1)));
        HelloInterface hello = (HelloInterface)proxyFactory.getProxy();
        hello.hello();

        System.out.println(proxyFactory.getTargetClass()); //class com.xiaoyuanzai.service.InvocationHandler.Hello
        System.out.println(proxyFactory.getTargetSource()); //SingletonTargetSource for target object [com.xiaoyuanzai.service.InvocationHandler.Hello@5d099f62]
        System.out.println(proxyFactory.getAdvisorCount()); //1
        System.out.println(Arrays.asList( proxyFactory.getAdvisors() )); //[org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [Pointcut.TRUE]; advice [com.xiaoyuanzai.service.InvocationHandler.ProxyFactoryMain$$Lambda$1/1199823423@37f8bb67]]

        System.out.println(".......................................");
        //代理类的接口HelloInterface、 SpringProxy、Advised、DecoratingProxy
        System.out.println(Arrays.asList( hello.getClass().getInterfaces() )); //[interface com.xiaoyuanzai.service.InvocationHandler.HelloInterface, interface org.springframework.aop.SpringProxy, interface org.springframework.aop.framework.Advised, interface org.springframework.core.DecoratingProxy]
        System.out.println(hello instanceof Proxy ); //true
        System.out.println(hello instanceof SpringProxy ); //true org.springframework.aop.SpringProxy这个是marker接口,空的,不用管,只是做个标记,框架会用到
        System.out.println(hello instanceof DecoratingProxy ); //true
        System.out.println(hello instanceof Advised ); //true
        System.out.println(hello.getClass());//class com.xiaoyuanzai.service.InvocationHandler.$Proxy0
        System.out.println(Proxy.isProxyClass( hello.getClass() ));//true
        System.out.println( AopUtils.isCglibProxy( hello ) );//false

        System.out.println(".......................................");
        //测试Advised接口、DecoratingProxy的内容
        Advised advised = (Advised)hello;
        System.out.println(advised.isExposeProxy()); //false
        System.out.println(advised.isFrozen()); //false

        System.out.println(".......................................");
        // Object的方法 ==== 所有的Object方法都不会被AOP代理(除了toString()) 这点需要注意
        System.out.println(hello.equals( new Object() ));//false
        System.out.println(hello.hashCode());
        System.out.println(hello.getClass());

        //其余方法都没被拦截  只有toString()被拦截了
        //你被拦截了:方法名为:toString 参数为--[]
        //com.xiaoyuanzai.service.InvocationHandler.Hello@5d099f62
    System.out.println(hello.toString());


    }
    }

    interface HelloInterface{

    void hello();
    }

    class Hello implements HelloInterface{
    @Override
    public void hello(){
    System.out.println("Hello world");
    }
    }
上面逻辑生成的就是JDK动态代理对象,核心就两步

1.addAdvice():添加advice前置通知器,并包装成DefaultPointcutAdvisor交给ProxyCreatorSupport

2.getProxy():本文关键,内部会new一个JdkDynmicAopProxy,并调用它的getProxy()获取动态代理对象,他JdkDynmicAopProxy实现了InvocationHandler接口,当调用目标方法时,会触发invocationHandler的invoke()方法,该方法内部会执行第一步添加的前置通知器,并最终执行原目标方法

5.1. JdkDynamicAopProxy

进入源码看看

// 它自己实现了InvocationHandler,处理器就是它自己,所以他会实现invoke方法
// final关键字代表了 包的访问权限
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

    /** use serialVersionUID from Spring 1.2 for interoperability. */
    private static final long serialVersionUID = 5531744639992436476L;
    private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);

    /** 保存当前AOP代理所有的配置信息  包括所有的增强器等等 */
    private final AdvisedSupport advised;

    private final Class<?>[] proxiedInterfaces;

    /** true:标记equals方法定义在接口上 */
    private boolean equalsDefined;
    /** true:hashCode方法定义在接口上 */
    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;
        // 这步就是去找 获取aop所有需要代理的接口
        // 最终Proxy的接口就是这里返回的所有接口(除了自己定义的接口,还有Spring默认的一些接口)
        // 大致过程如下:
        //1、获取Target对象自己实现的所有接口
        //2、是否添加`SpringProxy`这个接口:目标对象实现过就不添加了,没实现过就添加true
        //3、是否新增`Adviced`接口,注意不是Advice通知接口。 实现过就不实现了,没实现过并且advised.isOpaque()=false就添加(默认是会添加的)
        //4、是否新增DecoratingProxy接口。传入的参数decoratingProxy为true,并且没实现过就添加(显然这里,首次进来是会添加的)
        //5、代理类的接口一共是目标对象的接口+上面三个接口SpringProxy、Advised、DecoratingProxy(SpringProxy是个标记接口而已,其余的接口都有对应的方法的)
        //DecoratingProxy 这个接口Spring4.3后才提供

        this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
    }


    @Override
    public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
    }

    /** 真正创建JDK动态代理实例的地方 */
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        // this实现了InvocationHandler,处理器(InvocationHandler)就是自己,并new一个代理对象
        return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
    }


    // 找接口里有没有自己定义equals方法和hashCode方法,标记为true
    private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
        // 判断被代理的接口中是否定义了equals()、hashCode()方法,如果程序员在接口中手动定义了这两个方法,则也会进行代理
        // 否则这两个方法是不会走代理逻辑的
        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的大部分逻辑都是一样的
        */
        @Override
        @Nullable
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;

        // 拿到被代理对象
        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

        try {
        // 如果接口中没有定义equals()方法,且 实现类自己实现equals()方法则调用AOP这里的实现
        // hashCode同理
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
        return equals(args[0]);
    }
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
        return hashCode();
    }
        //DecoratingProxy的方法和Advised接口的方法  都是是最终调用了this.advised去执行的
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
        return AopProxyUtils.ultimateTargetClass(this.advised);
    }
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
        method.getDeclaringClass().isAssignableFrom(Advised.class)) {
        // 也是直接调用Advised接口中的方法,不走代理逻辑
        return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    }

        Object retVal;

        // 如果ProxyFactory的exposeProxy为true,则将代理对象设置到currentProxy这个ThreadLocal中去
        if (this.advised.exposeProxy) {
        //把我们的代理对象暴露到线程变量中
        oldProxy = AopContext.setCurrentProxy(proxy);
        setProxyContext = true;
    }

        // 被代理对象和代理类
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);


        // 代理对象在执行某个方法时,根据方法筛选出所有匹配的Advisor(通知advice+切入点pointcut),并适配成Interceptor,通过责任链模式 依此获取到
        // 参见DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice方法
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        //拦截器链为空
        if (chain.isEmpty()) {
        // 如果没有Advice,则直接调用目标方法
        // 对参数适配:处理一些数组类型的参数,表示一个(多个)参数(可变参数最终到此都是数组类型,所以最好是需要一次适配)
        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
        //直接调用目标方法
        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
    }
        else {
        //MethodInvocation是org.aopalliance.intercept这个包下的AOP联盟得标准接口
        // 创建一个ReflectiveMethodInvocation
        MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
        // 递归执行所有的拦截器链chain,则前置、后置等通知
        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帮我们实现的equals方法
        @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())) {
        // other是一个jdk动态代理产生的代理对象
        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();
    }

    }

注意:

1.生成出来的代理对象Spring都默认实现了接口:SpringProxy、DecoratingProxy、Advised,而CGLIB代理对象没有实现DecoratingProxy

2.里面两个重要方法,getProxy()方法负责拿到代理对象,invoke()方法负责在每次代理方法被调用时执行(除了实现类里自己写的方法(接口上没有的),其余方法统一都会进入代理得invoke()方法里面)

3.Object的toString()方法会被增强

5.2. ObjenesisCglibAopProxy

这个是CGLIB的demo,注意看里面没有接口类了,是通过生成代理类的class对象的形式,生成代理对象

main方法

public class ProxyFactoryMain {

   public static void main( String[] args ) {
      ProxyFactory proxyFactory = new ProxyFactory(new Hello());
      proxyFactory.addAdvice( ( MethodBeforeAdvice )( method, args1, target ) -> {
         System.out.println( "你被拦截了:方法名为:" + method.getName() + " 参数为--" + Arrays.asList( args1 ) );
      } );
      Hello hello = (Hello)proxyFactory.getProxy();
      hello.hello();
   }
}

class Hello {

   public void hello() {
      System.out.println( "Hello world" );
   }

}

在代码中可以看到ObjenesisCglibAopProxy继承了CglibAopProxy,重写了createProxyClassAndInstance()方法,用于生成代理实例

/**
 * ObjenesisCglibAopProxy是Spring4.0之后提供的
 */
@SuppressWarnings("serial")
class ObjenesisCglibAopProxy extends CglibAopProxy {

    private static final Log logger = LogFactory.getLog(ObjenesisCglibAopProxy.class);

    private static final SpringObjenesis objenesis = new SpringObjenesis();


    /**
    * Create a new ObjenesisCglibAopProxy for the given AOP configuration.
    * @param config the AOP configuration as AdvisedSupport object
    */
    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);
            }
        }
        // 如果proxyInstance还为null,再去拿到构造函数去new一个实例(指定参数的)
        if (proxyInstance == null) {
            // Regular instantiation via default constructor...
            try {
                Constructor<?> ctor = (this.constructorArgs != null ?
                                       proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
                                       proxyClass.getDeclaredConstructor());
                ReflectionUtils.makeAccessible(ctor);
                // 通过此构造函数  去new一个实例
                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;
    }

}

5.3. CglibAopProxy

这个类处理核心操作,getProxy()负责获取代理对象实例,DynamicAdvisedInterceptor#intercept()负责拦截目标方法做方法增强

class CglibAopProxy implements AopProxy, Serializable {

    @Override
	public Object getProxy() {
		return getProxy(null);
	}

	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
		}

		try {
			// 被代理的类
			Class<?> rootClass = this.advised.getTargetClass();
			Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

			Class<?> proxySuperClass = rootClass;
			// 如果被代理类本身就已经是Cglib所生成的代理类了
			if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
				// 获取真正的被代理类
				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 ClassLoaderAwareGeneratorStrategy(classLoader));

			// 获取和被代理类所匹配的Advisor
			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);
		}
		catch (CodeGenerationException | IllegalArgumentException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (Throwable ex) {
			// TargetSource.getTarget() failed
			throw new AopConfigException("Unexpected AOP exception", ex);
		}
	}

	protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
		enhancer.setInterceptDuringConstruction(false);
		enhancer.setCallbacks(callbacks);
		return (this.constructorArgs != null && this.constructorArgTypes != null ?
				enhancer.create(this.constructorArgTypes, this.constructorArgs) :
				enhancer.create());
	}

	/**
	 * Creates the CGLIB {@link Enhancer}. Subclasses may wish to override this to return a custom
	 * {@link Enhancer} implementation.
	 */
	protected Enhancer createEnhancer() {
		return new Enhancer();
	}

    /** CGLIB重写这个方法 */
	@Override
	public boolean equals(@Nullable Object other) {
		return (this == other || (other instanceof CglibAopProxy &&
				AopProxyUtils.equalsInProxy(this.advised, ((CglibAopProxy) other).advised)));
	}
	/** CGLIB重写这个方法 */
	@Override
	public int hashCode() {
		return CglibAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
	}

    /**
	 *  所有被代理的类(Target)的所有方法调用,都会进入DynamicAdvisedInterceptor#intercept()方法中(相当于JDK动态代理得invoke方法)
	 */
	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) {
					// Make invocation available if necessary.
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}

				// 拿到目标对象   这里就是使用targetSource的意义,它提供多个实现类,从而实现了更多的可能性
				// 比如:SingletonTargetSource  HotSwappableTargetSource  PrototypeTargetSource  ThreadLocalTargetSource等等
				target = targetSource.getTarget();
				Class<?> targetClass = (target != null ? target.getClass() : null);

				// 跟JdkDynamicAopProxy的invoke()方法的调用一样,获取拦截器
				// 代理对象在执行某个方法时,根据方法筛选出所有匹配的Advisor(通知advice+切入点pointcut),并适配成Interceptor,通过责任链模式 依此获取到
				// 参见DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice方法
				List<Object> 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是`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) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

        @Override
		public boolean equals(@Nullable 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();
		}
	}

注意:

1.和jdk一样只有toString()方法会被拦截

2.默认实现了SpringProxy、Advised接口

3.它和JDK不同的是,比如equals和hashCode等方法根本就不会进入intecept方法,而是在getCallbacks()那里就给特殊处理掉了


 

5.3.1. Objenesis

上面源码有提到SpringObjenesis,那下面就来具体讲一下。

创建对象有好多种方式,如new一个对象,通过构造器反射获取一个对象,又或者是用Objenesis的方式生成对象(绕过构造函数来创建对象)

Objenesis库可以在以下情况下用来实例化对象:
1. 对象没有无参构造函数:如果一个类没有公共的无参构造函数,那么使用传统的反射机制将无法直接实例化该对象。在这种情况下,Objenesis可以通过创建一个未完全初始化的对象进行实例化。
2. 构造函数不可访问(构造函数为private):有些类可能将它们的构造函数设置为私有或受保护的,这使得使用传统的反射方法来创建对象变得非常困难(class.newInstance)。Objenesis可以绕过构造函数的访问级别限制,使您可以实例化这些对象。
3. 性能优化:使用传统的反射机制创建对象时,Java虚拟机需要执行一系列复杂的操作来初始化对象。这可能会影响应用程序的性能。使用Objenesis库,您可以更高效地创建对象并提高应用程序的性能。
总之,Objenesis可用于那些没有公共的无参数构造函数或构造函数不可用的对象,或者需要更高效的对象实例化的情况下。

5.3.1.1. ObjenesisStd

import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

public class Main {
    public static void main(String[] args) throws Exception {
        //创建一个Objenesis实例
        Objenesis objenesis = new ObjenesisStd();

        //使用Objenesis创建一个对象(注意:没有调用构造函数)
        MyClass myClass = objenesis.newInstance(MyClass.class);

        //使用反射来设置对象的属性
        myClass.setName("My Object");
        myClass.setValue(123);

        //打印输出对象的属性
        System.out.println(myClass.getName());  //输出:My Object
        System.out.println(myClass.getValue()); //输出:123
    }
}

class MyClass {
    private String name;
    private int value;

    private MyClass() {
        //私有构造函数
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

5.3.1.2. ObjectInstantiator

ObjectInstantiator是Objenesis库提供的一个接口,可以用来创建特定类型的对象实例。和直接调用Objenesis.newInstance()方法不同,使用ObjectInstantiator可以更方便地重复创建同一类型的对象。ObjectInstantiator有一个唯一的方法newInstance(),它可以创建一个新的对象实例,不同的是,每次调用newInstance()时,都会返回一个新的实例。

public interface ObjectInstantiator<T> {
    T newInstance();
}

demo如下:

import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.objenesis.instantiator.ObjectInstantiator;

public class Main {
    public static void main(String[] args) throws Exception {
        //创建一个Objenesis实例
        Objenesis objenesis = new ObjenesisStd();

        //使用Objenesis创建一个ObjectInstantiator实例
        ObjectInstantiator<MyClass> myClassInstantiator =
        objenesis.getInstantiatorOf(MyClass.class);

        //使用ObjectInstantiator创建多个MyClass对象
        MyClass myClass1 = myClassInstantiator.newInstance();
        MyClass myClass2 = myClassInstantiator.newInstance();
        MyClass myClass3 = myClassInstantiator.newInstance();

        //打印输出对象的属性
        System.out.println(myClass1.getName());  //输出:null
        System.out.println(myClass2.getValue()); //输出:0
        System.out.println(myClass3.getName());  //输出:null
    }
}

class MyClass {
    private String name;
    private int value;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

在上面的示例中,我们使用Objenesis创建了一个ObjectInstantiator实例,然后使用该实例重复创建MyClass对象。在每次调用newInstance()方法时,都会返回一个新的MyClass对象实例。

所有的Objenesis类都在org.objenesis包中

5.3.1.3. SpringObjenesis

这是Spring对Objenesis接口的一个实现

Objenesis objenesis = new SpringObjenesis();

Spring为我们提供了一个isWorthTrying()方法:

// 是否需要尝试:也就是说,它是否还没有被使用过,或者已知是否有效。方法返回true,表示值得尝试
	// 如果配置的Objenesis Instantiator策略被确定为不处理当前JVM。或者系统属性"spring.objenesis.ignore"值设置为true,表示不尝试了
	// 这个在ObjenesisCglibAopProxy创建代理实例的时候用到了。若不尝试使用Objenesis,那就还是用老的方式用空构造函数吧
	public boolean isWorthTrying() {
		return (this.worthTrying != Boolean.FALSE);
	}

利用SpringObjenesis,即使没有空的构造函数也可以创建实例。

注意

JDK代理只能针对实现了接口的类以反射的方式生成代理,而不能针对类 ,所以也叫接口代理

CGLIB是针对类实现代理的,主要对指定的类以字节码转换的方式(ASM框架)生成一个子类,并重写其中的方法。

所以使用CGLIB做动态代理,必须要保证有一个空的构造函数。(那是之前,其实现在不需要了,因为我们有了Objenesis的帮助),但是类不能是Final的

关于final方法

- JDK代理:因为接口的方法不能使用final关键字,所以编译器就过不去

- CGLIB代理:final修饰某个方法后,不报错。但也不会拦截了

关于static方法

- JDK代理:static修饰接口上的方法,要求有body体(JDK8后支持)。但是因为子类不能@Override了,所以编译就报错了

- CGLIB代理:父类方法用static修饰后,子类也是无法进行重写的。因此不报错,但也不会拦截了

使用代理的时候,尽量不要使用final和static关键字

关于非public方法

- JDK代理:接口中的方法都是public的,所以对于它不存在这种现象

- CGLIB代理:记住结论 只有private的方法不能被代理(因为子类无法访问),其余的访问权限级别的,都能够被正常代理。 简单的说就是只要子类能够访问的权限,都能够被正常代理

6. 总结

1、JdkDynamicAopProxy 入口方法是 invoke() 方法,CGLIB 使用的是 DynamicAdvisedInterceptor.intercept()方法

2、JdkDynamicAopProxy使用的MethodInvocation 是: ReflectiveMethodInvocation 子类,

CGLIB 使用的是CglibMethodInvocation,它俩都是ProxyMethodInvocation接口的实现类。并且CglibMethodInvocation是继承自ReflectiveMethodInvocation

7. 参考文献

【小家Spring】详解Spring AOP的底层代理JdkDynamicAopProxy和ObjenesisCglibAopProxy的源码分析(介绍CGLIB使用中的坑)_YourBatman的博客-CSDN博客

JAVA系列:代理(Proxy) 源码分析_51CTO博客_java proxy 动态代理

Spring AOP系列(三) — 动态代理之JDK动态代理

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序源仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值