jdk动态代理原理解析

原文地址:https://www.cnblogs.com/gonjan-blog/p/6685611.html

想要理解jdk动态代理原理,需要对反射有一定的了解,然后再去思考下面两个问题:

  1. 为什么是基于接口的?
  2. 动态生成的代理类是什么样子?是如何执行的?

现在有一个接口以及它的实现类。现在需要在执行每个方法前后打印一条日志。

package proxy;
public interface Activity {
    void partake();
    void reward();
}
package proxy;
public class ActivityImpl implements Activity{

    @Override
    public void partake() {}

    @Override
    public void reward() {}

    public void check() {}
}

首先我们要知道ActivityImpl有哪些方法需要在执行前后打印日志,jdk动态代理是这样实现的:

  1. 通过反射,去得到ActivityImpl实现的所有接口
  2. 再得到所有接口中定义的方法

所以jdk动态代理需要基于接口。

那我们想要在执行每个方法前后打印日志,有什么办法呢?我们看一下jdk动态生成的代理类长什么样,是如何执行的:

// 打印出jdk动态生成代理类
public class test {
    public static void main(String[] args) {
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", ActivityImpl.class.getInterfaces());
        String path = "C:/Users/tacitodong/Desktop/testClass/ActivityImpl.class";
        try(FileOutputStream fos = new FileOutputStream(path)) {
            fos.write(classFile);
            fos.flush();
            System.out.println("代理类class文件写入成功");
        } catch (Exception e) {
            System.out.println("写文件错误");
        }
    }
}
// jdk动态生成的代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.Activity;

public final class $Proxy0 extends Proxy implements Activity {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    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 reward() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void partake() throws  {
        try {
            super.h.invoke(this, m4, (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("proxy.Activity").getMethod("reward");
            m4 = Class.forName("proxy.Activity").getMethod("partake");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

$Proxy0就是我们拿到的动态代理类,这个类是动态生成的,缓存在jvm中。使用时跟 ActivityImpl 几乎没有区别。但是当我们调用 $Proxy0 的partake或者reward方法时,内部其实执行的是 InvocationHandler 的 invoke 方法,通过传入不同的Method参数达到执行对应方法的目的。所以我们需要实现 InvocationHandler 接口,在执行方法前后打印日志。

public class LogDynamic implements InvocationHandler {

    private final Object subject;

    public LogDynamic(Object subject) {
        this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before...");
        method.invoke(subject, args);
        System.out.println("after...");
        return null;
    }     
}

到这里基本上就把整个流程串起来了。讲了这么多就是为了去理解下面这段代码,jdk动态代理是如何生成代理类,以及代理类是如何工作的

public static void main(String[] args) {
    InvocationHandler handler = new LogDynamic(new ActivityImpl());
    // 此处得到的activity就是代理类,跟我们打印出来的 $Proxy0 的内容是一样的。
    Activity activity =  (Activity)Proxy.newProxyInstance(handler.getClass().getClassLoader(),
            ActivityImpl.class.getInterfaces(), handler);
    activity.partake();
}

==============================================

cglib实现与之类似,是通过创建子类继承当前类,来实现对方法的代理。但是这种实现不需要被代理类依赖于接口。

public class ActivityService {
    public void partake() {

    }
}
package cglib;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before...");
        Object obj = methodProxy.invokeSuper(o,objects);
        System.out.println("after...");
        return obj;
    }
}
package cglib;

import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;

public class test {
    public static void main(String[] args) {
        // 可以打印出动态生成的代理类
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:/Users/tacitodong/Desktop/testClass");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(ActivityService.class);
        enhancer.setCallback(new CglibProxy());
        ActivityService activityService = (ActivityService) enhancer.create();
        activityService.partake();

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值