JAVA中的代理模式

568 阅读12分钟

1. 简介

为其他对象提供一个代理以控制对某个对象的访问。代理类主要负责为委托了(真实对象)预处理消息、过滤消息、传递消息给委托类,代理类不现实具体服务,而是利用委托类来完成服务,并将执行结果封装处理。

2. 代理分类

代理主要有静态代理,JDK动态代理Cglib动态代理3种方式,我们依次进行解读~

2.1 静态代理

一个简单的静态代理的例子可以从创建一个接口开始~这个接口里要写的方法就是我们的原始业务。

public interface WorkInterface {
    void doWork();
}

被代理的类,需要实现这个接口!并定义自己的业务。

public class Worker implements WorkInterface{
    @Override
    public void doWork() {
        System.out.println("实现业务!");
    }
}

同样的,我们的静态代理类也需要实现这个接口!并且在自己的doWork()方法里面调用我们的woker的原始方法,并加入我们代理时新加入的业务处理。

public class WorkerProxy implements WorkInterface{
    private WorkInterface worker = new Worker();
    @Override
    public void doWork() {
        System.out.println("Before invoke doWork" );
        worker.doWork();
        System.out.println("After invoke doWork");
    }
}

显而易见的,当我们在方法里调用我们的静态代理类时:

public static void main(String[] args) {
    WorkerProxy workerProxy = new WorkerProxy();
    workerProxy.doWork();
}
/**
Before invoke doWork
实现业务!
After invoke doWork
*/

我们实现了对代理对象的doWork()方法的代理,并且在方法里面实现了对原本业务流程之外的数据预处理和结果再处理等功能!

静态代理的缺点就是,由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。

2.2 JDK动态代理

2.2.1 简单使用

对于动态代理的举例,我们依旧使用上一节的例子~

public interface WorkInterface {
    void doWork();
}
public class Worker implements WorkInterface{
    @Override
    public void doWork() {
        System.out.println("实现业务!");
    }
}

为了实现一个能够为所有类服务的动态代理方法,想必我们需要实现一个方法,这个方法可以让我们把需要代理的对象传进去,并返回给我们一个代理对象,这个可以通过InvocationHandler来实现!

我们创建我们自己的ProxyHandler类,并且重写里面的invoke()方法,我们对原始业务的一些额外处理,就可以在这里进行定义!

public class ProxyHandler implements InvocationHandler {
    private Object object;
    public ProxyHandler(Object object){
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在实际业务的前后增加一些额外的处理
        System.out.println("Before invoke " + method.getName());
        method.invoke(object,args);
        System.out.println("After invoke " + method.getName());
        return null;
    }
}

既然已经有了这个方法,我们就可以开始进行操作了:

public class ProxyTest {
    public static void main(String[] args) {
        // 第一步,我们要有我们需要代理的目标对象
        WorkInterface worker = new Worker();
        // 第二步,我们要创建自己定义的handler,实际上有用的就是handler中的invoke方法(即我们自己定义的新业务逻辑)
        InvocationHandler handler = new ProxyHandler(worker);
        // 第三步,利用Proxy进行代理对象的创建
        WorkInterface workerProxy = (WorkInterface) Proxy
                .newProxyInstance(worker.getClass().getClassLoader(), worker.getClass().getInterfaces(), handler);
        workerProxy.doWork();
    }
}
/*输出:
Before invoke doWork
实现业务!
After invoke doWork
*/

可以看到,最后代理类执行与我们目标业务同名的方法的时候,按照我们在invoke()方法中设定的一样进行了对应的业务处理。同时,我们定义的ProxyHandler能够根据创建时传入对象的不同,实现对不同类的动态代理。

2.2.2 JDK动态代理底层实现

一个动态代理的实现主要有以下几个步骤:

  1. 通过实现 InvocationHandler 接口创建自己的调用处理器,即上节中的ProxyHandler
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface(本案例中就一个接口) 来创建动态代理类;
  3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  4. 通过构造函数创建动态代理类实例,构造时调用处理器(ProxyHandler)对象作为参数被传入。

首先我们从上一节中创建最终代理对象的Proxy.newProxyInstance()方法开始:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{	
    //检查传进来的handler是否为null,若是则抛异常
    Objects.requireNonNull(h);
    //校验系统权限
    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    //生成对象的代理类Class对象
    Class<?> cl = getProxyClass0(loader, intfs);

    //使用指定的调用处理程序获取代理类的构造函数对象
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        //获取到返回的代理类的构造器,用于最后构建代理类对象
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        //如果Class作用域为私有,通过 setAccessible 支持访问
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        //获取Proxy Class构造函数,创建Proxy代理实例。
        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);
    }
}

其中,使用了getProxyClass0来生成代理类:

private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }

    return proxyClassCache.get(loader, interfaces);
}

有趣的是,他首先进行了一个参数长度的确认,数据大小是很熟悉的65535。这一块是因为,在JVM的常量池里面,UTF-8编码的Unicode字符串在常量池中以CONSTANT_Utf8类型表示,而其存储数据的长度是一个无符号位的16位整数,因此理论上最大存储长度是2^16=65536,但由于null值用了两个字节来表示,所以存储数据的长度不能大于65535。

PS: 这里可以引申出一个有趣的String相关的小问题,一个字符串的最大长度到底是多少?

我们都知道String的底层实现是一个char[]数组,而一个数组的长度是Integer.MAX即整型数的最大值,那一个字符串的最大长度想必就是这个数值了。实际上,这是字符串在运行时的最大数值,而在编译期间,利用字面量进行赋值的字符串会因为JVM常量存储长度的限制,其长度无法超过65535。

public class StringNumTest {
    public static void main(String[] args) {
        StringBuffer buffer = new StringBuffer();
        //往buffer里面拼接65536个a
        for (int i = 0; i < 65536; i++) {
            buffer.append('a');
        }
        //赋值给一个字符串s,并不会报错
        String s = buffer.toString();
        System.out.println(s);
        //然而,当我们用字面量赋值的时候
        String s1 = "a...a"; //里面有65536个a
        //会报编译错误,字符串长度过长!!
    }
}

好了,回到正题,在验证完interface的长度后,调用了proxyClassCache.get()方法进行创建,简单的说,这个方法在代理类缓存里面寻找是否已经有副本继承了我们需要代理的接口,如果有的话直接返回,否则就利用ProxyClassFactory创建一个。

public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);
    //清理过期缓存实体
    expungeStaleEntries();
    //创建对这个key的weakCache
    Object cacheKey = CacheKey.valueOf(key, refQueue);

    //为这个key创建map中的键值映射,简单来说,我们可以理解为一个key对应了一个我们即将创建的代理类class对象,这个key是我们传进来的对应于我们想要代理的接口workInterface的classloader
    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;
        }
    }

    // subKey为指向我们想要代理的接口的弱引用
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        // 这里需要一个循环,是因为线程竞争的原因可能会失败,所以不断尝试,直到完成动态代理的创建
        if (supplier != null) {
            //在这个方法里面,根据之前对classloader和interface的弱引用,通过ProxyClassFactory创建了代理类class,并赋值给了value并返回
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }

        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                supplier = factory;
            }
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                supplier = factory;
            } else {
                supplier = valuesMap.get(subKey);
            }
        }
    }
}

supplier.get()方法中,调用了ProxyClassFactory.apply()方法,返回给定ClassLoader 和interfaces的代理类:

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) {
        }
        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");
            }
        }
    }
    //proxyPkg是目标代理类的生成路径
    if (proxyPkg == null) {
        // if no non-public proxy interfaces, use com.sun.proxy package
        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    }
    //代理类的名字
    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;

    //在这里!生成了我们代理类的字节码!
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces, accessFlags);
    try {
        //返回我们生成的代理类!
        return defineClass0(loader, proxyName,
                            proxyClassFile, 0, proxyClassFile.length);
    } catch (ClassFormatError e) {
        throw new IllegalArgumentException(e.toString());
    }
}
}

ProxyGenerator.generateProxyClass()中,生成了代理类的字节码!

public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
    ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
    //真正生成字节码的方法在这里~
    final byte[] var4 = var3.generateClassFile();
    //可以选择在执行结束后,是否保存生成的动态代理文件到本地
    if (saveGeneratedFiles) {
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                try {
                    int var1 = var0.lastIndexOf(46);
                    Path var2;
                    if (var1 > 0) {
                        Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                        Files.createDirectories(var3);
                        var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                    } else {
                        var2 = Paths.get(var0 + ".class");
                    }

                    Files.write(var2, var4, new OpenOption[0]);
                    return null;
                } catch (IOException var4x) {
                    throw new InternalError("I/O exception saving generated file: " + var4x);
                }
            }
        });
    }

    return var4;
}

真正生成字节码的方法是var3.generateClassFile(),如下:

private byte[] generateClassFile() {
    //第一步,下面的addProxyMethod方法是将接口中的方法和Object中的方法添加到代理方法中(proxyMethod)
    this.addProxyMethod(hashCodeMethod, Object.class);
    this.addProxyMethod(equalsMethod, Object.class);
    this.addProxyMethod(toStringMethod, Object.class);
    Class[] var1 = this.interfaces;
    int var2 = var1.length;

    int var3;
    Class var4;
    //获取接口中的所有方法
    for(var3 = 0; var3 < var2; ++var3) {
        var4 = var1[var3];
        Method[] var5 = var4.getMethods();
        int var6 = var5.length;

        for(int var7 = 0; var7 < var6; ++var7) {
            Method var8 = var5[var7];
            this.addProxyMethod(var8, var4);
        }
    }

    Iterator var11 = this.proxyMethods.values().iterator();

    List var12;
    while(var11.hasNext()) {
        var12 = (List)var11.next();
        checkReturnTypes(var12);
    }

    Iterator var15;
    try {
        //生成要代理的构造函数
        this.methods.add(this.generateConstructor());
        var11 = this.proxyMethods.values().iterator();

        while(var11.hasNext()) {
            var12 = (List)var11.next();
            var15 = var12.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
                this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                this.methods.add(var16.generateMethod());
            }
        }

        this.methods.add(this.generateStaticInitializer());
    } catch (IOException var10) {
        throw new InternalError("unexpected I/O Exception", var10);
    }

    if (this.methods.size() > 65535) {
        throw new IllegalArgumentException("method limit exceeded");
    } else if (this.fields.size() > 65535) {
        throw new IllegalArgumentException("field limit exceeded");
    } else {
        this.cp.getClass(dotToSlash(this.className));
        this.cp.getClass("java/lang/reflect/Proxy");
        var1 = this.interfaces;
        var2 = var1.length;

        for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];
            this.cp.getClass(dotToSlash(var4.getName()));
        }

        this.cp.setReadOnly();
        ByteArrayOutputStream var13 = new ByteArrayOutputStream();
        DataOutputStream var14 = new DataOutputStream(var13);

        try {
            var14.writeInt(-889275714);
            var14.writeShort(0);
            var14.writeShort(49);
            this.cp.write(var14);
            var14.writeShort(this.accessFlags);
            var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
            var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
            var14.writeShort(this.interfaces.length);
            Class[] var17 = this.interfaces;
            int var18 = var17.length;

            for(int var19 = 0; var19 < var18; ++var19) {
                Class var22 = var17[var19];
                var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
            }

            var14.writeShort(this.fields.size());
            var15 = this.fields.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                var20.write(var14);
            }

            var14.writeShort(this.methods.size());
            var15 = this.methods.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                var21.write(var14);
            }

            var14.writeShort(0);
            return var13.toByteArray();
        } catch (IOException var9) {
            throw new InternalError("unexpected I/O Exception", var9);
        }
    }
}

后面字节码怎么生成的实在是看不懂了=.=,最后我们来看一下最终生成的代理类长什么样子!

public final class $Proxy0 extends Proxy implements WorkInterface {
    //所有的方法都由反射得来,看代码尾部的static代码块
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
	
    //构造函数,传入一个handler,我们在这个handler里面重写了invoke()方法以定义自己的逻辑
    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 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 void doWork() throws  {
        try {
            //重点看这里,我们调用了父类Proxy里面的handler,在构造这个代理类的时候,我们就将我们自己定义的handler传入了类中,作为一个其父类的一个内部对象,所以我们在这里利用super调用h(handler),并调用里面的invoke方法(自己定义的新业务逻辑),执行代理类的doWork方法!
            super.h.invoke(this, m3, (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);
        }
    }
	
    //利用反射,我们通过类名和方法名获取到对应的方法!
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.emoli.test.service.WorkInterface").getMethod("doWork");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

2.2.3 JDK动态代理总结

基于上述的源码分析,我们可以得出JDK动态代理的几个核心关键点:

  • 为了自定义代理类要实现的逻辑,我们要创建一个自己的继承了InvocationHandler的handler,并重写里面的invoke()方法;
  • 从生成的代理类代码可以看出,其是一个Proxy类的子类,并且需要同时实现我们原始方法的接口,即本例中的WorkInterface
  • 这样,JDK动态代理的限制就显而易见了,代理类和原始类必须都继承于同样的目标接口,而代理的业务内容也存在于目标接口方法里面;

2.3 Cglib动态代理

2.3.1 简单使用

我们同样使用一个简单的例子来看一看cglib动态代理的使用~我们创建一个Student类,其中有一个方法doStudy()

public class Student {

    public void doStudy(){
        System.out.println("开始学习!");
    }
}

与JDK动态代理类似的,我们在Cglib动态代理中需要定义一个方法拦截器:

public class StudyInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before study");
        Object object = methodProxy.invokeSuper(obj, args);
        System.out.println("after study");
        return object;
    }
}

最后,我们进行测试!

public static void main(String[] args) {
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\Users\\emoli\\IdeaProjects\\demo\\src\\main\\java\\com\\emotest\\cglib");
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Student.class);
    enhancer.setCallback(new StudyInterceptor());

    Student stu = (Student) enhancer.create();
    stu.doStudy();
}
/*输出:
before study
开始学习
after study
*/

可以看到,其实现了与JDK动态代理一样的功能。

2.3.2 Cglib动态代理底层实现

可以看到,首先我们创建了一个Enhancer对象,这个对象有一些类似于JDK动态代理中的Proxy类,其担负着创建代理类等的一系列工作。

Enhancer类继承了AbstractClassGenerator类,其无参构造使用了父类的无参构造,并传入了自己的class名

private static final Source SOURCE = new Source(Enhancer.class.getName());

public Enhancer() {
    super(SOURCE);
}

AbstractClassGenerator的构造方法:

protected AbstractClassGenerator(AbstractClassGenerator.Source source) {
    // 默认的生成策略
    this.strategy = DefaultGeneratorStrategy.INSTANCE;
    // 默认的命名策略
    this.namingPolicy = DefaultNamingPolicy.INSTANCE;
    // 默认的使用缓存,DEFAULT_USE_CACHE是一个boolean值,默认为true,缓存的用处和JDK动态代理中类似,让已经创建过的代理类不用重复创建
    this.useCache = DEFAULT_USE_CACHE;
    this.source = source;
}

在生成了Enhancer对象后,我们首先使用setSuperclass()方法设定父类,这里就可以看出,Cglib动态代理是基于继承目标类来实现的,并不要求目标业务方法来源于一个接口。

public void setSuperclass(Class superclass) {
    // 判断是否为一个接口
    if (superclass != null && superclass.isInterface()) {
        this.setInterfaces(new Class[]{superclass});
    // 是否为一个Object.class
    } else if (superclass != null && superclass.equals(Object.class)) {
        this.superclass = null;
    // 否则,就直接赋给superclass
    } else {
        this.superclass = superclass;
    }
}

接下来,设置了Enhancer的回调,传入了我们定义的MethodInterceptor,回调怎么使用,我们在后续代码中再研究~

public void setCallback(Callback callback) {
    this.setCallbacks(new Callback[]{callback});
}

public void setCallbacks(Callback[] callbacks) {
    if (callbacks != null && callbacks.length == 0) {
        throw new IllegalArgumentException("Array cannot be empty");
    } else {
        this.callbacks = callbacks;
    }
}

前面的操作都比较好理解,想必最重要的操作就在enhancer.create()中!

public Object create() {
    this.classOnly = false;
    this.argumentTypes = null;
    // 调用了createHelper()
    return this.createHelper();
}

private Object createHelper() {
    // 首先进行一个预检查
    this.preValidate();
    Object key = KEY_FACTORY.newInstance(
        // 继承的目标类
        this.superclass != null ? this.superclass.getName() : null, 
        // 不是接口则为null
        ReflectUtils.getNames(this.interfaces), 
        // 当callback不为多个时不需要filter,为null
        this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter), 
        // callback类型为MethodInterceptor
        this.callbackTypes, 
        // 使用工厂,默认为true
        this.useFactory, 
        // 默认为true
        this.interceptDuringConstruction, 
        // 序列版本ID,默认为null
        this.serialVersionUID);
    
    this.currentKey = key;
    // AbstractClassGenerator的create方法,传入key,key中包含了这个cglib代理要代理的目标类和一些配置
    Object result = super.create(key);
    return result;
}

createHelper()中,首先执行了preValidate()方法:

private void preValidate() {
    if (this.callbackTypes == null) {
        // 确认我们callback的类的类型,在这个测试案例里面,类型就是MethodInterceptor;
        this.callbackTypes = CallbackInfo.determineTypes(this.callbacks, false);
        // 有效的callback类型~
        this.validateCallbackTypes = true;
    }

    if (this.filter == null) {
        // 判断是否有多个callback,如果有的话,就需要定义一个filter
        if (this.callbackTypes.length > 1) {
            throw new IllegalStateException("Multiple callback types possible but no filter specified");
        }
		// 如果没有多个callback,则把filter置为默认空值
        this.filter = ALL_ZERO;
    }

}

之后,利用KEY_FACTORY.newInstance()构建了一个key!KEY_FACTORYEnhancer类中的一个EnhancerKey对象,其利用keyFactory创建:

private static final EnhancerKey KEY_FACTORY =
    (EnhancerKey)KeyFactory.create(EnhancerKey.class, KeyFactory.HASH_ASM_TYPE, null);

这里传入了一个KeyFactory.HASH_ASM_TYPE,其是创建hashcode的策略:

public static final HashCodeCustomizer HASH_ASM_TYPE = new HashCodeCustomizer() {
    public boolean customize(CodeEmitter e, Type type) {
        if (Constants.TYPE_TYPE.equals(type)) {
            e.invoke_virtual(type, GET_SORT);
            return true;
        }
        return false;
    }
};

调用了KeyFactory.create()来构建一个KEY_FACTORY

public static KeyFactory create(Class keyInterface, KeyFactoryCustomizer first, List<KeyFactoryCustomizer> next) {
    return create(keyInterface.getClassLoader(), keyInterface, first, next);
}

public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer,
                                List<KeyFactoryCustomizer> next) {
    // Generator类是KeyFactory的内部类,同时其继承了AbstractClassGenerator
    Generator gen = new Generator();
    // 设置接口为EnhancerKey
    gen.setInterface(keyInterface);
	// 绑定定制器
    if (customizer != null) {
        gen.addCustomizer(customizer);
    }
    if (next != null && !next.isEmpty()) {
        for (KeyFactoryCustomizer keyFactoryCustomizer : next) {
            gen.addCustomizer(keyFactoryCustomizer);
        }
    }
    // 设置类加载器
    gen.setClassLoader(loader);
    // 创建一个KEY_FACTORY并返回
    return gen.create();
}

使用gen.create()进行KEY_FACTORY的创建:

public KeyFactory create() {
    // 设置名称前缀EnhancerKey
    setNamePrefix(keyInterface.getName());
    // 最终,这个gen还是调用了父类AbstractClassGenerator的create方法
    return (KeyFactory)super.create(keyInterface.getName());
}

AbstractClassGeneratorcreate()方法在代理的生成中被调用多次,我们重点看一下:

protected Object create(Object key) {
        try {
            // 获取类加载器,因为我们前面将目标代理类传入为了superclass,那这里的classloader就和我们的代理类使用同级的AppClassloader
            ClassLoader loader = getClassLoader();
            // 定义缓存
            Map<ClassLoader, ClassLoaderData> cache = CACHE;
            // 看看缓存里边有无我们需要的classloader的data,没有就创建一个
            ClassLoaderData data = cache.get(loader);
            if (data == null) {
                synchronized (AbstractClassGenerator.class) {
                    // 这里加锁了,因为多线程,所以要二次校验
                    cache = CACHE;
                    data = cache.get(loader);
                    // 如果还没有,就new一个并更新Cache	
                    if (data == null) {
                        Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                        // 重点来了,一个ClassLoaderData对象到底是什么?
                        data = new ClassLoaderData(loader);
                        newCache.put(loader, data);
                        CACHE = newCache;
                    }
                }
            }
            // key是EnhancerKey的名字
            this.key = key;
            // 调用ClassLoaderData的get方法,从缓存获取Class实例或通过asm生成字节码文件返回Class实例。
            Object obj = data.get(this, getUseCache());
            if (obj instanceof Class) {
                // 创建实例!
                return firstInstance((Class) obj);
            }
            return nextInstance(obj);
        } catch (RuntimeException e) {
            throw e;
        } catch (Error e) {
            throw e;
        } catch (Exception e) {
            throw new CodeGenerationException(e);
        }
    }

上述代码的第18行构建了一个新的ClassLoaderData对象,我们来看一下他的构造方法:

public ClassLoaderData(ClassLoader classLoader) {
    if (classLoader == null) {
        throw new IllegalArgumentException("classLoader == null is not yet supported");
    }
    // 对classloader的弱引用,提到弱引用,自然就想到是为了防止内存泄漏,可以以threadLocal类比
    this.classLoader = new WeakReference<ClassLoader>(classLoader);
    // Function是一个接口,在这里重写了接口中的apply方法
    Function<AbstractClassGenerator, Object> load =
        new Function<AbstractClassGenerator, Object>() {
        public Object apply(AbstractClassGenerator gen) {
            Class klass = gen.generate(ClassLoaderData.this);
            return gen.wrapCachedClass(klass);
        }
    };
    generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);
}

之后,调用了ClassLoaderDataget()方法,从缓存获取Class实例或通过asm生成字节码文件返回Class实例。

public Object get(AbstractClassGenerator gen, boolean useCache) {
    if (!useCache) {
        return gen.generate(ClassLoaderData.this);
    } else {
        // 我们采用缓存,并用generatedClasses.get()方法,获得对目标类的虚引用
        // 在这个当前的逻辑中,目的是创建一个EnhancerKey,因此这里的cachedValue为指向EnhancerKey的虚引用
        Object cachedValue = generatedClasses.get(gen);
        // unwrapCachedValue表示解开虚引用,即拿到真实的class对象以生成实例!
        return gen.unwrapCachedValue(cachedValue);
    }
}

至此,一个EnhancerKey类型的KEY_FACTORY实例就创建成功了!

让我们回到enhancer下的createHelper()下,可以看到我们生成了一个key,并调用了super.create(key)将这个key传入了enhancer父类的create()方法中,实际上也是使用了AbstractClassGeneratorcreate()方法。我们传入的key内包含了我们目标类的全限定名,传入的方法callback以及其他的构造一个类的信息,最后其返回了一个继承于目标类的代理类。

至此,AbstractClassGenerator这个类的作用我们已经很清楚了,它根据我们传入的信息,构建一个继承于我们目标类的Cglib代理类,在其内部会生成代理类的字节码文件,并返回一个实例化对象。

我们来看一看生成的字节码里面的核心部分,即Cglib代理类重写的我们的目标类中的方法sayHello()

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

public final void sayHello() {
  // var10000就是我们定义的MethodInterperceptor
  MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
  if (var10000 == null) {
    CGLIB$BIND_CALLBACKS(this);
    var10000 = this.CGLIB$CALLBACK_0;
  }
  if (var10000 != null) {
    // 调用回调方法中的intercept方法,即我们重写的方法
    var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
  } else {
    super.sayHello();
  }
}

我们把我们自己写的StudyInterceptor拿回来对比着看一看~

public class StudyInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {				
        //这里传入的obj是我们生成的代理类,传入的method是目标类中的原始方法引用,args是方法参数,methodProxy是一个方法代理
        System.out.println("before study");
        Object object = methodProxy.invokeSuper(obj, args);
        System.out.println("after study");
        return object;
    }
}

重点看!我们除去自己添加的逻辑,真正原始目标方法的执行是通过methodProxy来实现的:

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
  try {
    // 为目标类的方法建立索引
    init();
    FastClassInfo fci = fastClassInfo;
    // 调用代理类中索引为i2的方法,实际上就是调用了我们目标类的原始方法。
    return fci.f2.invoke(fci.i2, obj, args);
  } catch (InvocationTargetException e) {
    throw e.getTargetException();
  }
}

这里要注意这里使用了一个FastClass类,简单的说,这个类在MethodInterceptor中,进行init()并创建所有方法的引用索引,这样我们就可以通过一个引用数组进行对应下标的方法访问,从而避免了基于反射获取方法带来的性能损失!

2.3.3 Cglib动态代理总结

基于上述的源码分析,我们可以得出以下几个关键点:

  • Cglib动态代理是以继承来实现的,其并不需要目标类继承于一个接口;
  • 在代理过程中,Cglib并没有使用反射进行方法的获取,而是使用了FastClass进行快速的目标方法获取,提升了性能;
  • 既然是基于继承来实现,那Cglib的缺陷也非常明显,其无法代理用Final关键词修饰的类和方法。