JDK和CGLIB动态代理

JDK动态代理

定义接口:

public interface HelloWorld {
    void sayHelloWorld();
}

实现代理类,继承自InvocationHandler:

public class JdkProxyDemo implements InvocationHandler {
    //真实对象
    private Object target = null;

    //代理对象-获取被代理接口实例对象 - 即生成了一个代理类
    //1.建立代理对象和真实对象的关系
    Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }


    /**
     * Description: 代理方法逻辑
     *
     * @param proxy  :代理对象,即bind方法产生的对象
     * @param method :当前调度方法
     * @param args   :当前方法参数
     * @return java.lang.Object:代理结果返回
     */
    //2.实现代理逻辑方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入代理逻辑方法");
        System.out.println("在调用真实方法之前的服务...");
        Object object = method.invoke(target, args);
        System.out.println("在调用真实方法之后的服务...");
        return object;
    }
}

测试类:

public class JdkProxyTest {
    public static void main(String[] args) {
        //以下代码打印出代理类com/sun/proxy/$Proxy0.class
        //原理是sun/misc/ProxyGenerator.class的generateProxyClass方法生成字节码后,判断了此标识位
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        JdkProxyDemo jdk = new JdkProxyDemo();
        //绑定关系
        HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl());
        //此时的proxy是一个代理对象,他会进入代理类(即$Proxy0.class)的逻辑方法invoke里
        //而代理类中的invoke方法,又调用了InvocationHandler接口的invoke方法...
        proxy.sayHelloWorld();
    }
}

生成的代理类:


public final class $Proxy0 extends Proxy implements HelloWorld {
    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 sayHelloWorld() 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.kyee.etltool.practice.designpattern.dynamicProxy.HelloWorld").getMethod("sayHelloWorld");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

CGLIB动态代理

需要代理的类:

public class HelloWorldImpl  {
    public void sayHelloWorld() {
        System.err.println("hello world...");
    }
}

CGLIB代理类:

public class CglibProxyDemo implements MethodInterceptor {
    /**
     * Description: 生成CGLIB代理对象
     *
     * @param cls :class类
     * @return java.lang.Object
     */
    public Object getProxy(Class cls) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(cls);//设置增强类型
        enhancer.setCallback(this);//设定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor
        //生成并返回代理对象(封装在了拦截器的第一个参数里...)
        //HelloWorldImpl$$EnhancerByCGLIB$$ba1f40a9@473b46c3
        return enhancer.create();
    }

    /**
     * Description:
     *
     * @param o           :代理对象,
     * @param method      :方法
     * @param objects     :方法参数
     * @param methodProxy :方法代理
     * @return java.lang.Object
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用真实对象前");
        //CGLIB反射调用真实方法
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println();
        System.out.println("调用真实对象后。。。");
        return result;
    }
}

测试类:

public class CglibProxyTest {
    public static void main(String[] args) {
        //将生成的类放在c盘的这个路径下
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\codemaker");
        CglibProxyDemo cglibProxyDemo = new CglibProxyDemo();
        //生成代理对象,制定代理逻辑类
        HelloWorldImpl h = (HelloWorldImpl) cglibProxyDemo.getProxy(HelloWorldImpl.class);
        h.sayHelloWorld();
    }
}

运行后可以看到输出:

CGLIB debugging enabled, writing to 'C:\codemaker'
调用真实对象前
hello world...
调用真实对象后。。。

对应文件夹下有三个class文件:
在这里插入图片描述
打开第二个可以看到:


public class HelloWorldImpl$$EnhancerByCGLIB$$ba1f40a9 extends HelloWorldImpl 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$sayHelloWorld$0$Method; //被代理方法
    private static final MethodProxy CGLIB$sayHelloWorld$0$Proxy; //代理方法
    ...

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        //代理类
        Class var0 = Class.forName("com.kyee.etltool.practice.designpattern.dynamicProxy.impl.HelloWorldImpl$$EnhancerByCGLIB$$ba1f40a9");
        //被代理类
        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$sayHelloWorld$0$Method = ReflectUtils.findMethods(new String[]{"sayHelloWorld", "()V"}, (var1 = Class.forName("com.kyee.etltool.practice.designpattern.dynamicProxy.impl.HelloWorldImpl")).getDeclaredMethods())[0];
        CGLIB$sayHelloWorld$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHelloWorld", "CGLIB$sayHelloWorld$0");
    }

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

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

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

从代理对象反编译源码可以知道,代理对象继承于被代理类,拦截器调用intercept()方法,intercept()方法由自定义CglibProxyDemo implements MethodInterceptor实现,所以,最后调用CglibProxyDemo中的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值