代理模式介绍

目录

一、概念

二、结构 

三、静态代理 

四、动态代理

4.1 JDK动态代理

4.1.1 代码演示

4.1.2 原理

4.1.3 源码解读 

4.2 cglib动态代理 

4.2.1 代码演示

4.2.2 源码解读

4.3 javassist动态代理

4.3.1 代码演示

4.3.2 原理分析

五、总结 

 六、参考博文


一、概念

     由于某种原因,不能直接访问目标对象,需要引入一个中间对象来代理以控制目标对象的访问。java中的代理按照代理类生成时机不同又分为静态代理(在编译期生成代理对象)和动态代理(在运行期生成代理对象)。

二、结构 

代理模式分为三种角色:

  • 抽象主题类:通过接口或抽象类型声明真实主题和代理对象实现的业务方法。
  • 真实主题类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制和扩展真实主题的功能。

三、静态代理 

public interface ISubject {
    void doSomeThings();
}

/**
 * 真实对象
 */
class RealSubject implements ISubject{

    @Override
    public void doSomeThings() {
        System.out.println("doSomeThings");
    }
}

/**
 * 代理对象
 */
class ProxySubject implements ISubject{

    private RealSubject realSubject = new RealSubject();

    @Override
    public void doSomeThings() {
        System.out.println("before do some things");
        realSubject.doSomeThings();
        System.out.println("after do some things");
    }

    public static void main(String[] args) {
        //创建代理类对象
        ProxySubject proxySubject = new ProxySubject();
        proxySubject.doSomeThings();
    }
}

四、动态代理

4.1 JDK动态代理

4.1.1 代码演示
public interface ISubject {
    void doSomeThings();
}

/**
 * 真实对象
 */
class RealSubject implements ISubject{

    @Override
    public void doSomeThings() {
        System.out.println("doSomeThings");
    }
}

/**
 * 代理工厂
 */
class ProxyFactory {

    private RealSubject realSubject = new RealSubject();

    /**
     * 获取代理对象
     */
    public ISubject getProxySubject(){

        /**
         * ClassLoader loader:类加载器,用于加载代理类,可以通过目标对象获取类加载器
         * Class<?>[] interfaces: 代理类实现的接口的字节码对象
         * InvocationHandler h :代理对象的调用处理程序
         */
        final Class<? extends RealSubject> subjectClass = realSubject.getClass();
        ISubject proxySubject = (ISubject)Proxy.newProxyInstance(
                subjectClass.getClassLoader(),
                subjectClass.getInterfaces(),
                new InvocationHandler() {
                    /**
                     * @param proxy 代理对象
                     * @param method 将接口中的方法封装成Method类型的对象
                     * @param args 接口方法的参数
                     * @return 接口方法的返回值
                     */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("before do some things");
                Object obj = method.invoke(realSubject, args);
                System.out.println("after do some things");
                return obj;
            }
        });
        return proxySubject;

    }

    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory();
        ISubject proxySubject = factory.getProxySubject();
        proxySubject.doSomeThings();
    }
}
4.1.2 原理

根据Arthas获得生成的代理类

package com.sun.proxy;

import com.example.ISubject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0
extends Proxy
implements ISubject {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

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

    public final String toString() {
        try {
            return (String)this.h.invoke(this, m2, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void doSomeThings() {
        try {
            this.h.invoke(this, m3, null);
            return;
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode() {
        try {
            return (Integer)this.h.invoke(this, m0, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.example.ISubject").getMethod("doSomeThings", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            return;
        }
        catch (NoSuchMethodException noSuchMethodException) {
            throw new NoSuchMethodError(noSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException classNotFoundException) {
            throw new NoClassDefFoundError(classNotFoundException.getMessage());
        }
    }
}
  • 代理类($Proxy0)和真实对象实现类同样的接口
  • 代理类将实现InvocationHandler的子类传递给父类Proxy
  • 在代理类实现接口,在接口调用父类的invoke方法
4.1.3 源码解读 

Proxy.newProxyInstance解读

@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
                                          InvocationHandler h)
        
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
		//java的安全管理器,可参考文章https://www.cnblogs.com/yiwangzhibujian/p/6207212.html
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        // 获取(缓存中如果有)或者生成目标代理类
        Class<?> cl = getProxyClass0(loader, intfs);

            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            // 通过构造函数去生成一个目标代理类的实例。
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
			
			// 如果构造函数并不是public修饰的,那么设置代理类可以通过反射来访问
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        
    }

       以上代码和实际的源码有所不同,精简了一下,方便阅读。上面函数主要完成两件事:生成代理类的字节码对象和通过代理类的字节码对象创建实例。另外需要关注一下@CallerSensitive,该注解标注 jdk内有些方法,jvm的开发者认为这些方法危险,不希望开发者调用,就把这种危险的方法用 @CallerSensitive修饰,并在“jvm”级别检查,并且@CallerSensitive 有个特殊之处,必须由 启动类classloader加载(如rt.jar ),才可以被识别。

     获得代理类的字节码对象,会根据反射调用代理类有参构造器,参数类型是InvocationHandler,其实在代理类中的构造器会调用其父类Proxy,来初始化Proxy类的成员变量protected InvocationHandler h; 之后代理类实现接口的方法里,其实是调用父类Proxy中InvocationHandler类型的变量的invoke方法。

接下来会先从缓存里获取目标代理类,如果缓存没有才创建代理类,在Proxy类定义一个成员变量

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

构造WeakCache对象需要传入两个类型分别是KeyFactory和ProxyClassFactory的参数,这两个类都是Proxy的静态内部类。

KeyFactory源码如下

 private static final class KeyFactory
        implements BiFunction<ClassLoader, Class<?>[], Object>
    {
        @Override
        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
            switch (interfaces.length) {
                case 1: return new Key1(interfaces[0]); // the most frequent
                case 2: return new Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new KeyX(interfaces);
            }
        }
    }

KeyFactory实现函数式接口BiFunction,重写apply方法,该方法主要根据目标类继承接口的个数不同,生成相应接口的虚引用,这些Key*类都继承WeakReference。

 ProxyClassFactory源码如下

 private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // 代理类名前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // 代理类名后缀
        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) {
                
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
				// 判断相同名字的接口是否是同一个Class对象
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
				
                // 验证是否是接口类型
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                // 验证是否有重复的实现
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            //如果目标类实现的接口,有不是public修饰的。那么目标代理类生成的路径会在该接口所在目录下
             
            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) {
                // 如果目标类所实现的接口都是被public修饰的,那么会动态生成在com.sun.proxy下,而且被public final修饰
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

           
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                
                .....
            }
        }
    }

ProxyClassFactory就是生成代理类的工厂,需要注意的时,设置代理类所在的包路径。判断依据:

  • 如果存在非public的接口并且不在同一个包内,那么抛出异常。
  • 如果存在非public的接口,但是在同一个包内,那么在该接口所在的路径就是目标类的生成路径。
  • 如果所有接口都是public类型的,那么目标类的路径设置为com.sum.proxy.

前面讲到代理会先从缓存里获取,那我们看看这个缓存的构造吧

 private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
        = new ConcurrentHashMap<>();

从WeaCache这个缓存数据结构里,可以看出一二级key整合起来对应一个value的组合,即(key,sub-key)-> (value),其中key是指代理的classLoader,sub-key指目标函数的interfaces,value指$Proxy.class

接下来看WeaChe核心实现get源码

    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);
         //对已经被gc的实例从缓存中移除
        expungeStaleEntries();

        /**
		* 根据传入的key(classloader)和引用队列包装成一个CacheKey类型的key
		* 如果key为null,则返回一个Object类型的对象,否则返回一个CacheKey类型的对象
		* CacheKey继承WeakReference,是一个弱引用类型的
		*/
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        //通过CacheKey获取到二级缓存实例
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
		    //如果不存在该一级缓存,则对该一级缓存进行初始化
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        /**
		* 通过sub-key函数将key/parameter计算出sub-key,并且这里计算的结果不允许为空
		* key是classloader,parameter是interfaces
		* 计算方式已经在前面KeyFactory源码讲过了
		*/
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
		//从二级缓存中获取结果获取器
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;
        //这里进入死循环,直到获取到结果为止
        while (true) {
            if (supplier != null) {
			     /**
				 *这里获取到值可能是一个工厂或者一个缓存实例
				 *如果返回一个Factory类型的工厂,Factory实现了Supplier接口,在apply方法就会生成代理类
				 *而在apply方法又调用ProxyClassFactory的方法来真正生成代理类
				 */
			     
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }

            //这里懒加载工厂,实例化一个内置Factory,该Factory实现了Supplier
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
			    //这里如果supplier为空,则直接将factory放入二级缓存
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
			     //如果supplier非空,但是获取值为空则进行替换二级缓存中factory(或者supplier)
                if (valuesMap.replace(subKey, supplier, factory)) {
                    
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }
  • 根据一级键(根据类加载器classLoader)、二级键(根据接口interfaces)从缓存中来获取目标代理类对象supplier 。
  • supplier可能是一个创建成功的动态代理对象。也可能是一个创建代理对象的工厂Factory(第一次的话就是他)。
  • 因为第一次动态代理的时候,缓存肯定是null。因此实际上就会做一些初始化操作。
  • 就是创建一个Factory工厂,通过工厂来创建一个动态代理对象(最终的对象),这里实际调用ProxyClassFactory的方法来生成的。

4.2 cglib动态代理 

4.2.1 代码演示
/**
 * 真实对象
 */
class RealSubject {

    public void doSomeThings() {
        System.out.println("doSomeThings");
    }
}

/**
 * 代理工厂
 */
class ProxyFactory{

    /**
     * 获取代理对象
     */
    public RealSubject getProxySubject(){

        //创建Enhancer对象,类似于JDK代理中的Proxy类
        Enhancer enhancer = new Enhancer();
        //设置父类的字节码对象
        enhancer.setSuperclass(RealSubject.class);
        //设置回调函数,这里参数是MethodInterceptor的子类
        enhancer.setCallback(new MethodInterceptor() {
            /**
             * @param o           代理对象(增强的对象)  
             * @param method      被拦截的方法(需要增强的方法)  
             * @param objects        方法入参  
             * @param methodProxy 用于调用原始方法 保存方法的一些信息  
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("before do some things");
                Object returnValue = methodProxy.invokeSuper(o, objects);
                System.out.println("after do some things");
                return returnValue;
            }
        });
        //创建代理对象
        RealSubject proxyObject = (RealSubject) enhancer.create();

        return proxyObject;

    }

    public static void main(String[] args) {

        ProxyFactory proxyFactory = new ProxyFactory();
        final RealSubject proxySubject = proxyFactory.getProxySubject();
        proxySubject.doSomeThings();


    }
    
}
4.2.2 源码解读

通过以下代码:System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "F:\\项目\\demo\\proxy");

可以输出代理类字节码文件

 这三个文件有什么作用呢,且听我细细道来哈。

1)代理类

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.example;

import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class RealSubject$$EnhancerByCGLIB$$2244f8c3 extends RealSubject implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$doSomeThings$0$Method;
    private static final MethodProxy CGLIB$doSomeThings$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.example.RealSubject$$EnhancerByCGLIB$$2244f8c3");
        Class var1;
        CGLIB$doSomeThings$0$Method = ReflectUtils.findMethods(new String[]{"doSomeThings", "()V"}, (var1 = Class.forName("com.example.RealSubject")).getDeclaredMethods())[0];
        CGLIB$doSomeThings$0$Proxy = MethodProxy.create(var1, var0, "()V", "doSomeThings", "CGLIB$doSomeThings$0");
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$1$Method = var10000[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
    }

    final void CGLIB$doSomeThings$0() {
        super.doSomeThings();
    }

    public final void doSomeThings() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$doSomeThings$0$Method, CGLIB$emptyArgs, CGLIB$doSomeThings$0$Proxy);
        } else {
            super.doSomeThings();
        }
    }

    final boolean CGLIB$equals$1(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$2() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
    }

    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final Object CGLIB$clone$4() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -944907599:
            if (var10000.equals("doSomeThings()V")) {
                return CGLIB$doSomeThings$0$Proxy;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$4$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$1$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$2$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$3$Proxy;
            }
        }

        return null;
    }

    public RealSubject$$EnhancerByCGLIB$$2244f8c3() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        RealSubject$$EnhancerByCGLIB$$2244f8c3 var1 = (RealSubject$$EnhancerByCGLIB$$2244f8c3)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        RealSubject$$EnhancerByCGLIB$$2244f8c3 var10000 = new RealSubject$$EnhancerByCGLIB$$2244f8c3();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        RealSubject$$EnhancerByCGLIB$$2244f8c3 var10000 = new RealSubject$$EnhancerByCGLIB$$2244f8c3();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        RealSubject$$EnhancerByCGLIB$$2244f8c3 var10000 = new RealSubject$$EnhancerByCGLIB$$2244f8c3;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }

        return var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

从反编译的代理类字节码文件可以得出以下结论:

(1)代理通过继承目标类,并重写目标类方法实现代理的。

(2)对于父类的每个方法,代理里都生成两个方法,分别是:一个是重写父类的方法,一个是CGLIB$xxxx$x方法,前者是实现目标方法的增强的。接下来我重点分析代理类的doSomeThings方法。

public final void doSomeThings() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$doSomeThings$0$Method, CGLIB$emptyArgs, CGLIB$doSomeThings$0$Proxy);
        } else {
            super.doSomeThings();
        }
    }

先判断MethodInterceptor是否为null,也就是判断是否实现了该接口,如果没有,调用CGLIB$BIND_CALLBACKS方法来获取拦截对象,CGLIB$BIND_CALLBACKS代码如下

private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        RealSubject$$EnhancerByCGLIB$$2244f8c3 var1 = (RealSubject$$EnhancerByCGLIB$$2244f8c3)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

(1)该方法会先从CGLIB$THREAD_CALLBACKS中get拦截对象,如果获取不到的话,再从CGLIB$STATIC_CALLBACKS来获取

(2)如果获取到则走代理,否则认为该方法不需要代理

(3)然后调用MethodInterceptor的intercept方法

var10000.intercept(this, CGLIB$doSomeThings$0$Method, CGLIB$emptyArgs, CGLIB$doSomeThings$0$Proxy);

参数分别是代理类对象本身,本拦截的方法对象,方法入参和用于调用被拦截方法的方法代理对象,那第四个参数有什么作用呢?其实第四个参数决定了cglib代理高效的原因。cglib没有通过反射调用目标类方法,而是为每个方法分配索引,通过索引查找具体方法,类似于直接调用。

 前面生成的三个文件,除了代理类,剩下的是索引文件,接下来看一下MethodInterceptor的intercept方法

 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("before do some things");
                Object returnValue = methodProxy.invokeSuper(o, objects);
                System.out.println("after do some things");
                return returnValue;
            }

继续看MethodProxy的invokeSuper方法

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

 init()方法主要完成对MethodProxy类成员变量fastClassInfo初始化,初始化完成后可知fci中对应的两个成员变量分别对应上面生成的两个索引文件,对于

fci.f2.invoke(fci.i2, obj, args);

  • fci为封装了两个FastClass的静态类FastClassInfo
  • f2为代理类的文件索引类
  • i2为具体方法索引

FastClassInfo类结构如下

private static class FastClassInfo
    {
        FastClass f1;
        FastClass f2;
        int i1;
        int i2;
    }

FasfClassInfo包含两个FastClass类型的成员变量,其中FastClass有两个重要方法

getIndex用来生成对应方法的索引的,生成规则主要根据方法名+方法的描述符实现的,

invoke根据索引调用相应的方法

abstract public Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException;

abstract public int getIndex(Signature sig);

索引字节码文件代码如下

public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -944907599:
            if (var10000.equals("doSomeThings()V")) {
                return 0;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 1;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 2;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 3;
            }
        }

        return -1;
    }


public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        RealSubject var10000 = (RealSubject)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                var10000.doSomeThings();
                return null;
            case 1:
                return new Boolean(var10000.equals(var3[0]));
            case 2:
                return var10000.toString();
            case 3:
                return new Integer(var10000.hashCode());
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }


4.3 javassist动态代理

4.3.1 代码演示
/**
 * 代理工厂
 */
class MyProxyFactory {

    /**
     * 获取代理对象
     */
    public Object getProxy(Class<?> clazz) throws Exception {
        // 创建代理工厂
        ProxyFactory proxyFactory = new ProxyFactory();
        // 设置需要创建子类的父类
        proxyFactory.setSuperclass(clazz);

        Object proxy = proxyFactory.createClass().newInstance();
        ((ProxyObject) proxy).setHandler(new MethodHandler() {
            @Override
            public Object invoke(Object self, Method thisMethod, Method proceed, Object[] objects) throws Throwable {
                System.out.println("before do some things");
                Object returnValue = proceed.invoke(self, objects);
                System.out.println("after do some things");
                return returnValue;
            }
        });
        return proxy;
    }


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

        MyProxyFactory factory = new MyProxyFactory();
        RealSubject proxy = (RealSubject) factory.getProxy(RealSubject.class);
        proxy.doSomeThings();

    }

}
4.3.2 原理分析

在生成代理类之前,通过给ProxyFactory类的成员变量writeDirectory赋值,会得到生成的代理类文件。

public class RealSubject_$$_jvst886_0 extends RealSubject implements ProxyObject {
    private MethodHandler handler;
    public static byte[] _filter_signature;
    public static final long serialVersionUID;
    private static Method[] _methods_;

    public RealSubject_$$_jvst886_0() {
        this.handler = RuntimeSupport.default_interceptor;
        super();
    }

    public final Object _d0clone() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        Method[] var1 = _methods_;
        return (Object)this.handler.invoke(this, var1[0], var1[1], new Object[0]);
    }

    public final void _d1doSomeThings() {
        super.doSomeThings();
    }

    public final void doSomeThings() {
        Method[] var1 = _methods_;
        this.handler.invoke(this, var1[2], var1[3], new Object[0]);
    }

    public final boolean _d2equals(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        Method[] var2 = _methods_;
        return (Boolean)this.handler.invoke(this, var2[4], var2[5], new Object[]{var1});
    }

    public final void _d3finalize() throws Throwable {
        super.finalize();
    }

    protected final void finalize() throws Throwable {
        Method[] var1 = _methods_;
        this.handler.invoke(this, var1[6], var1[7], new Object[0]);
    }

    public final int _d5hashCode() {
        return super.hashCode();
    }

    public final int hashCode() {
        Method[] var1 = _methods_;
        return (Integer)this.handler.invoke(this, var1[10], var1[11], new Object[0]);
    }

    public final String _d8toString() {
        return super.toString();
    }

    public final String toString() {
        Method[] var1 = _methods_;
        return (String)this.handler.invoke(this, var1[16], var1[17], new Object[0]);
    }

    static {
        Method[] var0 = new Method[24];
        Class var1 = Class.forName("com.example.RealSubject_$$_jvst886_0");
        RuntimeSupport.find2Methods(var1, "clone", "_d0clone", 0, "()Ljava/lang/Object;", var0);
        RuntimeSupport.find2Methods(var1, "doSomeThings", "_d1doSomeThings", 2, "()V", var0);
        RuntimeSupport.find2Methods(var1, "equals", "_d2equals", 4, "(Ljava/lang/Object;)Z", var0);
        RuntimeSupport.find2Methods(var1, "finalize", "_d3finalize", 6, "()V", var0);
        RuntimeSupport.find2Methods(var1, "hashCode", "_d5hashCode", 10, "()I", var0);
        RuntimeSupport.find2Methods(var1, "toString", "_d8toString", 16, "()Ljava/lang/String;", var0);
        _methods_ = var0;
        serialVersionUID = -1L;
    }

    public void setHandler(MethodHandler var1) {
        this.handler = var1;
    }

    public MethodHandler getHandler() {
        return this.handler;
    }

    Object writeReplace() throws ObjectStreamException {
        return RuntimeSupport.makeSerializedProxy(this);
    }
}
  1. javassist与cglib类似,不需要目标类实现接口,也是通过继承目标类的方式来增强相应的方法的。

五、总结 

        这篇文章写了大约有半个月吧,每次都是下班回家看看,研究一下,当然,还有很多不足吧,鉴于个人水平有限,只能尽力而为,欢迎读者指正,共同进步,谢谢。

六、参考博文

  1. javassist使用指南_mChenys的博客-CSDN博客
  2. 万字长文解析CGLib动态代理源码!_人生逆旅我亦行人的博客-CSDN博客
  3. Spring | Aop核心 | Cglib源码详细解析_张书康的博客-CSDN博客
  4. cglib动态代理原理分析(含部分源码分析)_Klurdge的博客-CSDN博客
  5. cglib动态代理源码分析_51CTO博客_cglib源码
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值