原文地址:https://www.cnblogs.com/gonjan-blog/p/6685611.html
想要理解jdk动态代理原理,需要对反射有一定的了解,然后再去思考下面两个问题:
- 为什么是基于接口的?
- 动态生成的代理类是什么样子?是如何执行的?
现在有一个接口以及它的实现类。现在需要在执行每个方法前后打印一条日志。
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动态代理是这样实现的:
- 通过反射,去得到ActivityImpl实现的所有接口
- 再得到所有接口中定义的方法
所以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();
}
}