likes
comments
collection
share

设计模式-深度分析代理模式

作者站长头像
站长
· 阅读数 20

# 七大软件设计原则 # 设计模式-工厂模式 # 设计模式-单例模式 # 设计模式-原型模式 # 设计模式-策略模式 # 设计模式-责任链模式 # 设计模式-建造者模式

代理模式(Proxy Pattern) 是一种结构型设计模式, 让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。代理模式给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式的英文叫做Proxy或Surrogate,它是一种对象结构型模式。

代理模式的通用UML类图分析

设计模式-深度分析代理模式 主要包含以下三种角色:

  1. 抽象主题角色(Subject):主要职责是声明真实主题与代理的共同接口方法,该类可以是接口也可以是抽象类。
  2. 真实主题角色(RealSubject):该类也被称为被代理类,该类定义的代理所表示的真实对象,是负责执行系统真正的逻辑业务对象。
  3. 代理主题角色(Proxy):也被称为代理类,其内部持有RealSubject的引用,因此具备完全的对RealSubject的代理权,客户端调用代理对象的方法,同时也调用被代理对象的方法,但是会在代理对象前后增加一些处理代码

在代码中一般代理会被理解为代码增强,实际上就是在执行方法的前后添加一段逻辑,而调用这是不知道的,代理还被分为静态代理和动态代理

代理模式的通用写法

Subject:

public interface Subject {
    void request();
}

RealSubject:

public class RealSubject implements Subject{
    @Override
    public void request() {
        System.out.println("原始类处理请求");
    }
}

Proxy:

public class Proxy implements Subject{
    private Subject subject;

    public Proxy(Subject subject) {
        this.subject = subject;
    }


    @Override
    public void request() {
        before();
        this.subject.request();
        after();
    }

    private void before(){
        System.out.println("处理请求之前");
    }

    private void after(){
        System.out.println("处理请求之后");
    }
}

客户端调用:

public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Proxy proxy = new Proxy(realSubject);
        proxy.request();
    }
}

静态代理

这种代理方式需要代理对象和目标对象实现一样的接口,且代理类的代码是在运行之前就需要写好的 优点是:可以在不修改目标对象的前提下扩展目标对象的功能。

缺点也很明显

  1. 如果接口需要增加一个方法对应的代理类和被代理类都需要添加新的实现。
  2. 冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。

代码示例

比如买房,通常卖家只有房源,而卖家一般是没有房源的所以需要找到中介提供房源然后卖房。其中卖房的人就是被代理类,中介相当于代理类。

public interface IPerson {
    void sellHouse();
}
public class Seller implements IPerson{
    @Override
    public void sellHouse() {
        System.out.println("我要卖房");
    }
}
public class Intermediary implements IPerson {

    private final IPerson person;

    public Intermediary(IPerson person){
        this.person = person;
    }


    @Override
    public void sellHouse() {
        before();
        person.sellHouse();
        after();
    }

    private void before(){
        System.out.println("发布房源");
    }

    private void after(){
        System.out.println("交易完成");
    }
}

动态代理

动态代理利用了JDK API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。动态代理又被称为JDK代理或接口代理(也可以使用cglib动态生成代理对象)

基于JDK实现动态代理

代码示例

还是上述的例子我们用JDK动态代理来实现(接口以及卖家代码都不变,新增代理处理类)

public class JdkIntermediary implements InvocationHandler {

    private IPerson target;

    public IPerson getInstance(IPerson target){
        this.target = target;
        Class<?> clz = target.getClass();
        return (IPerson)Proxy.newProxyInstance(clz.getClassLoader(),clz.getInterfaces(),this);
    }

    private void before(){
        System.out.println("发布房源");
    }

    private void after(){
        System.out.println("交易完成");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(this.target, args);
        after();
        return result;
    }
}
public class Test {
    public static void main(String[] args) {
        IPerson person = new Seller();
        JdkIntermediary jdkIntermediary = new JdkIntermediary();
        IPerson instance = jdkIntermediary.getInstance(person);
        instance.sellHouse();

    }
}

看上去可能有些人说JdkIntermediary不就是代理类吗不也是在运行之前生成的吗,但是其实JdkIntermediary并不是代理类,它可以理解成代理处理程序我们可以断点看一下 设计模式-深度分析代理模式 真正的代理类是$Proxy0这个类是在运行时生成的。

优点:接口中新增方法不需要再像静态代理来一样每个方法都实现一遍了,维护比较方便 缺点:被代理类必须实现接口

自己实现JDK动态代理

JDK实现动态代理的原理其实很简单,就是采用字节重组重新生成对象来代替原始对象,以达到动态代理的目的,这里我们可以使用ProxyGenerator取到代理对象class文件的字节码我们可以输出到磁盘然后通过反编译查看对应的代码如下:

public class Test {
    public static void main(String[] args) {
        IPerson person = new Seller();
        JdkIntermediary jdkIntermediary = new JdkIntermediary();
        IPerson instance = jdkIntermediary.getInstance(person);
        instance.sellHouse();
        byte[] $Proxy0s = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{IPerson.class});
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("/Users/xzkj/Desktop/java_study/$Proxy0.class");
            fileOutputStream.write($Proxy0s);
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import com.example.demo.proxy.demo.IPerson;
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 IPerson {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    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 sellHouse() throws  {
        try {
            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.example.demo.proxy.demo.IPerson").getMethod("sellHouse");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

设计模式-深度分析代理模式 其中h就是实现 InvocationHandler的代理处理类,可以发现这里就是调用的处理类的 invoke方法,其中 m3就是对应的方法

发现其实底层也是实现了接口的所有方法,只不过这块实现的代码不再是我们自己书写而是JDK帮我们实现

总结一下大致的不步骤如下:

  1. 获取被代理对象的引用,并且获取它的所有的接口(反射获取)
  2. JDK动态代理类重新成成一个新的类,同时新的类要实现被代理类实现的所有接口
  3. 动态生成java代码,新加的业务逻辑方法由一定的逻辑代码调用
  4. 编译
  5. 加载到JVM中运行

首先InvocationHandler肯定是要的我们可以自己实现一个这个类就叫TDInvocationHandler具体代码如下:

public interface GPInvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
}

就是定义一个接口,当然这里也可以使用原来的InvocationHandler类 还有一个就是需要自定义ClassLoader的类需要重写 findClass方法应为 loadClass方法中如果没有加载到jvm的类会调用 findClass方法查找,而JDK中的findClass是直接抛出异常的需要自己去实现

public class TDClassLoader extends ClassLoader {

    private final File classPathFile;
    public TDClassLoader(){
        String classPath = Objects.requireNonNull(TDClassLoader.class.getResource("")).getPath();
        this.classPathFile = new File(classPath);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        String className = TDClassLoader.class.getPackage().getName() + "." + name;
        if(classPathFile  != null){
            File classFile = new File(classPathFile,name.replaceAll("\.","/") + ".class");
            if(classFile.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try{
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte [] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1){
                        out.write(buff,0,len);
                    }
                    return defineClass(className,out.toByteArray(),0,out.size());
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}

实现也很简单其实就是冲磁盘中读取就行 最后实现Proxy

public class TDProxy {

    public static final String ln = "\r\n";

    public static Object newProxyInstance(ClassLoader classLoader, Class<?> [] interfaces, TDInvocationHandler h){
       try {
           //1、动态生成源代码.java文件
           String src = generateSrc(interfaces);

//           System.out.println(src);
           //2、Java文件输出磁盘
           String filePath = TDProxy.class.getResource("").getPath();
//           System.out.println(filePath);
           File f = new File(filePath + "$Proxy1.java");
           FileWriter fw = new FileWriter(f);
           fw.write(src);
           fw.flush();
           fw.close();

           //3、把生成的.java文件编译成.class文件
           JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
           StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
           Iterable<? extends JavaFileObject> iterable = manage.getJavaFileObjects(f);

          JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
          task.call();
          manage.close();

           //4、编译生成的.class文件加载到JVM中来
          Class<?> proxyClass =  classLoader.loadClass("$Proxy1");
          Constructor<?> c = proxyClass.getConstructor(TDInvocationHandler.class);
           boolean delete = f.delete();

           //5、返回字节码重组以后的新的代理对象
           return c.newInstance(h);
       }catch (Exception e){
           e.printStackTrace();
       }
        return null;
    }

    private static String generateSrc(Class<?>[] interfaces){
            StringBuilder sb = new StringBuilder();
            sb.append(TDProxy.class.getPackage()).append(";").append(ln);
            sb.append("import ").append(interfaces[0].getName()).append(";").append(ln);
            sb.append("import java.lang.reflect.*;" + ln);
            sb.append("public class $Proxy1 implements ").append(interfaces[0].getName()).append("{").append(ln);
                sb.append("TDInvocationHandler h;" + ln);
                sb.append("public $Proxy1(TDInvocationHandler h) { " + ln);
                    sb.append("this.h = h;");
                sb.append("}" + ln);
                for (Method m : interfaces[0].getMethods()){
                    Class<?>[] params = m.getParameterTypes();

                    StringBuilder paramNames = new StringBuilder();
                    StringBuilder paramValues = new StringBuilder();
                    StringBuilder paramClasses = new StringBuilder();

                    for (int i = 0; i < params.length; i++) {
                        Class<?> clazz = params[i];
                        String type = clazz.getName();
                        String paramName = toLowerFirstCase(clazz.getSimpleName());
                        paramNames.append(type).append(" ").append(paramName);
                        paramValues.append(paramName);
                        paramClasses.append(clazz.getName()).append(".class");
                        if(i > 0 && i < params.length-1){
                            paramNames.append(",");
                            paramClasses.append(",");
                            paramValues.append(",");
                        }
                    }

                    sb.append("public ").append(m.getReturnType().getName()).append(" ").append(m.getName()).append(
                            "(").append(paramNames.toString()).append(") {").append(ln);
                        sb.append("try{" + ln);
                            sb.append("Method m = ").append(interfaces[0].getName()).append(".class.getMethod("").append(m.getName()).append("",new Class[]{").append(paramClasses.toString()).append("});").append(ln);
                            sb.append(hasReturnValue(m.getReturnType()) ? "return " : "").append(getCaseCode("this.h" +
                                    ".invoke(this,m,new Object[]{" + paramValues + "})", m.getReturnType())).append(
                                            ";").append(ln);
                        sb.append("}catch(Error _ex) { }");
                        sb.append("catch(Throwable e){" + ln);
                        sb.append("throw new UndeclaredThrowableException(e);" + ln);
                        sb.append("}");
                        sb.append(getReturnEmptyCode(m.getReturnType()));
                    sb.append("}");
                }
            sb.append("}" + ln);
            return sb.toString();
    }


    private static Map<Class,Class> mappings = new HashMap<Class, Class>();
    static {
        mappings.put(int.class,Integer.class);
    }

    private static String getReturnEmptyCode(Class<?> returnClass){
        if(mappings.containsKey(returnClass)){
            return "return 0;";
        }else if(returnClass == void.class){
            return "";
        }else {
            return "return null;";
        }
    }

    private static String getCaseCode(String code,Class<?> returnClass){
        if(mappings.containsKey(returnClass)){
            return "((" + mappings.get(returnClass).getName() +  ")" + code + ")." + returnClass.getSimpleName() + "Value()";
        }
        return code;
    }

    private static boolean hasReturnValue(Class<?> clazz){
        return clazz != void.class;
    }

    private static String toLowerFirstCase(String src){
        char [] chars = src.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

}

发现其实就是个代码拼接的过程

使用如下:

public class CustomIntermediary implements TDInvocationHandler {

    private IPerson target;

    public IPerson getInstance(IPerson target){
        this.target = target;
        Class<?> clz = target.getClass();
        return (IPerson) TDProxy.newProxyInstance(clz.getClassLoader(),clz.getInterfaces(),this);
    }

    private void before(){
        System.out.println("发布房源");
    }

    private void after(){
        System.out.println("交易完成");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(this.target, args);
        after();
        return result;
    }
public class Test {
    public static void main(String[] args) {
        IPerson person = new Seller();
        CustomIntermediary jdkIntermediary = new CustomIntermediary();
        IPerson instance = jdkIntermediary.getInstance(person);
        instance.sellHouse();
    }
}

基于Cglib实现动态代理

上文中的JDK实现动态代理,被代理类必须要实现接口,原理是生成的代理类也实现该接口然后把所有的方法实现一遍。这样做还是有局限性。没有实现接口的类就不能使用动态代理了,Cglib帮我们实现了没有实现接口的类如何实现动态代理

代码实现
public class CglibIntermediary implements MethodInterceptor {


    public Object getInstance(Class<?> clz){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    private void before(){
        System.out.println("发布房源");
    }

    private void after(){
        System.out.println("交易完成");
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object result = methodProxy.invokeSuper(o,objects);
        after();
        return result;
    }
}
public class Seller {
    public void sellHouse() {
        System.out.println("我要卖房");
    }
}
public class Test {
    public static void main(String[] args) {
        CglibIntermediary cglibIntermediary = new CglibIntermediary();
        Seller seller = (Seller) cglibIntermediary.getInstance(Seller.class);
        seller.sellHouse();
    }
}
原理分析

大概分析逻辑和上文一致我们主要看一下cglib帮我们生成的源码就行

在上文的代码中加上一句代码如下:

public class Test {
    public static void main(String[] args) {
        //利用CGlib的代理类可以将内存中的.class文件写入到本地磁盘
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/xzkj/Desktop/java_study/$Proxy0_cglib_class");
        CglibIntermediary cglibIntermediary = new CglibIntermediary();
        Seller seller = (Seller) cglibIntermediary.getInstance(Seller.class);
        seller.sellHouse();
    }
}

然后会对应生成文件夹,文件夹中有是三个文件 设计模式-深度分析代理模式 通过代码调试只要代理类应该是第一个 设计模式-深度分析代理模式

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

package com.example.demo.proxy.demo.cglib;

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

public class Seller$$EnhancerByCGLIB$$2368730a extends Seller 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$sellHouse$0$Method;
    private static final MethodProxy CGLIB$sellHouse$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.demo.proxy.demo.cglib.Seller$$EnhancerByCGLIB$$2368730a");
        Class var1;
        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");
        CGLIB$sellHouse$0$Method = ReflectUtils.findMethods(new String[]{"sellHouse", "()V"}, (var1 = Class.forName("com.example.demo.proxy.demo.cglib.Seller")).getDeclaredMethods())[0];
        CGLIB$sellHouse$0$Proxy = MethodProxy.create(var1, var0, "()V", "sellHouse", "CGLIB$sellHouse$0");
    }

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

    public final void sellHouse() {
        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$sellHouse$0$Method, CGLIB$emptyArgs, CGLIB$sellHouse$0$Proxy);
        } else {
            super.sellHouse();
        }
    }

    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 -1003175481:
                if (var10000.equals("sellHouse()V")) {
                    return CGLIB$sellHouse$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 Seller$$EnhancerByCGLIB$$2368730a() {
        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) {
        Seller$$EnhancerByCGLIB$$2368730a var1 = (Seller$$EnhancerByCGLIB$$2368730a)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);
        Seller$$EnhancerByCGLIB$$2368730a var10000 = new Seller$$EnhancerByCGLIB$$2368730a();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        Seller$$EnhancerByCGLIB$$2368730a var10000 = new Seller$$EnhancerByCGLIB$$2368730a();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        Seller$$EnhancerByCGLIB$$2368730a var10000 = new Seller$$EnhancerByCGLIB$$2368730a;
        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();
    }
}

通过上述代码也可以看出来CGlib原理也很简单就是继承被代理类然后重写所有被代理类的方法 设计模式-深度分析代理模式 冲这块代码可以看出调用方法的逻辑是如果实现了MethodInterceptor接口则会实现intercept方法否则会实现父类的方法我们在实现intercept的方法的时候又调用了MethodProxyinvokeSuper方法,再看invokeSuper的源码 设计模式-深度分析代理模式 这里有疑问的电视fci是啥f2又是啥 设计模式-深度分析代理模式 发现f2就是 FastClass继续找实在哪赋值的 设计模式-深度分析代理模式 设计模式-深度分析代理模式 找到这里发现似曾相识了,在看生成的代理类 设计模式-深度分析代理模式 而对应的上图中调用的fic.i2如下图: 设计模式-深度分析代理模式 此时就需要看一下编译后的另外两个类了(这两个类对应着代理类的FastClass和被代理类的FastClass,应为这里只调用了代理类的方法所以只看代理类的FastClass) 设计模式-深度分析代理模式 设计模式-深度分析代理模式 发现就是一个索引 最后就可以看 invoke方法了 设计模式-深度分析代理模式 设计模式-深度分析代理模式 就是调用代理类的CGLIB$sellHouse$0方法,最后再返回到代理类 该方法就是调用父类的方法也就是被代理类的方法

总结一下调用的流程图如下: 设计模式-深度分析代理模式

需要注意的是GClib也是有弊端的被代理类的方法如果被 final修饰了则不能被代理,应为不能被重写

JDK和CGlib实现动态代理的区别

  1. JDK动态代理是实现了被代理的接口,CGlib继承然后重写
  2. 两者都是在运行期间生成字节码,而JDK是直接写Class字节码,而CGlib是通过ASM框架写Class字节码,所以一块是CGLib更加复杂生成代理类的效率要稍微第一点
  3. JDK是通过反射机制调用的而CGLib是通过FastClass机制调用方法的所以CGLib的效率更高
转载自:https://juejin.cn/post/7166074984484470814
评论
请登录