JDK动态代理是如何通过反射机制实现的?源码解析说到动态代理必须得先说Class对象。 一个Class对象(可通过Cla
什么是Class对象?
说到动态代理必须得先说Class对象。
一个Class对象(可通过Class.forName("")获取),代表正在运行中的java应用的类和接口,通过反射机制可以在运行时获取类信息,如:类名、成员属性、构造方法等。
其中 枚举类(enum)是一种特殊的类,注解 属于 一种接口 ,java中所有注解(@interface)都隐形地继承Annotation接口。
数组类也属于Class类,他的Class类对象被同类型数组(元素类型、数组维度相同)共享,具体看Class#getName()的说明。
什么是反射机制?
Java 反射机制是在运行时分析类、获取类信息、访问类的成员变量和方法的一种机制。可以动态地创建对象、调用方法、修改属性,增加了程序的灵活性和可扩展性。
什么是JDK动态代理?
JDK 动态代理是一种在运行时动态生成代理对象的机制。它基于接口实现,通过反射机制在运行时创建代理类并拦截对目标对象方法的调用,可在方法调用前后添加额外逻辑,如日志记录、权限校验等,实现对目标对象的功能增强,而无需修改目标对象的代码。
假设有这么个接口和实现类
接口IService
public interface IService {
public void hello();
public void say(String name);
public void goods();
}
接口IService的实现类 ServiceImpl
public class ServiceImpl implements IService {
@Override
public void hello() {
System.out.println("Hello China!");
}
@Override
public void say(String name) {
System.out.println("say()");
}
@Override
public void goods() {
System.out.println("goods()");
}
}
如果客户要求你在ServiceImpl 中的每个方法 执行前和执行后 分别输出 "目标方法执行前的输出。”和"目标方法执行后的输出。”,你是不是会想到这样:
public class ServiceProxy {
private IService service;
public ServiceProxy(IService service){
this.service=service;
}
public void hello() {
System.out.println("目标方法执行前的输出。");
service.hello();
System.out.println("目标方法执行后的输出。");
}
@Override
public void say(String name) {
System.out.println("目标方法执行前的输出。");
service.say(name);
System.out.println("目标方法执行后的输出。");
}
@Override
public void goods() {
System.out.println("目标方法执行前的输出。");
service.goods();
System.out.println("目标方法执行后的输出。");
}
}
//然后再main方法中执行
IService service = new ServiceImpl();
ServiceProxy proxy = new ServiceProxy(service);
proxy.hello();
proxy.say("hello");
proxy.goods();
固然可以实现需求,但这无疑造成了代码冗余,也不利于后期代码的维护。
那么我们是不是可以在运行时拦截目标方法,然后将额外的需求织入其中并生成代理对象,最后通过反射机制,使用Method对象、目标对象以及方法参数来定位目标方法并执行?这就是接下来讲的JDK动态代理。
实现步骤
首先我们的代理类要实现 InvocationHandler 接口
public class ServiceProxy implements InvocationHandler {
private IService realService;
public ServiceProxy(IService realService) {
this.realService = realService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("目标方法执行前的输出。");
//通过反射来动态的调用目标方法
Object result = method.invoke(realService, args);
System.out.println("目标方法执行后的输出。");
return result;
}
//获取代理对象
public Object getProxy() {
return Proxy.newProxyInstance(realService.getClass().getClassLoader(), realService.getClass().getInterfaces(),
this);
}
}
然后编写测试类
public class ProxyTest {
public static void main(String[] args) {
//实例化目标对象
IService real = new ServiceImpl();
//传入目标对象,创建代理类
ServiceProxy proxy = new ServiceProxy(real);
//生成代理对象
IService service = (IService) proxy.getProxy();
//通过代理对象调用增强后的方法以及目标方法
service.hello();
//将生成的代理类的 class 文件保存到本地,方便反编译后查看
createProxyClassFile();
}
@SuppressWarnings("unused")
private static void createProxyClassFile() { // 将jdk生成的动态代理类的.class文件存放到本地
String name = "$ServiceProxy";
byte[] data = ProxyGenerator.generateProxyClass(name, new Class[] { IService.class });
FileOutputStream out = null;
try {
out = new FileOutputStream(name + ".class");
System.out.println((new File(name)).getAbsolutePath());
out.write(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != out)
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
源码解析
查看反编译后的代理类代码
public final class $ServiceProxy extends Proxy implements IService {
private static Method m1;
private static Method m5;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public $ServiceProxy(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject) {
try {
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void goods() {
try {
this.h.invoke(this, m5, null);
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void hello() {
try {
this.h.invoke(this, m4, null);
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void say(String paramString) {
try {
this.h.invoke(this, m3, new Object[] { paramString });
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode() {
try {
return ((Integer)this.h.invoke(this, m0, null)).intValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m5 = Class.forName("com.cen.proxy.IService").getMethod("goods", new Class[0]);
m4 = Class.forName("com.cen.proxy.IService").getMethod("hello", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.cen.proxy.IService").getMethod("say", new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
} catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
} catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
}
我们可以看到,代理类先通过Class.forName 去获取被代理接口的Class对象,然后再调用Class对象的getMethod方法,通过方法名和方法传参来返回一个目标方法的Method对象
Class.forName("com.cen.proxy.IService").getMethod("hello", new Class[0])
该Method对象会在$ServiceProxy调用方法的时候使用到,他将会作为参数传入
ServiceProxy#invoke(Object proxy, Method method, Object[] args)
并被使用
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(realService, args);
return result;
}
例如: hello()的调用,调用链是这样的:
步骤1. main方法
service.hello()
步骤2. $ServiceProxy的static代码块
m4 = Class.forName("com.cen.proxy.IService").getMethod("hello", new Class[0])
步骤3. $ServiceProxy#hello()
public final void hello() {
try {
this.h.invoke(this, m4, null);
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
步骤4. ServiceProxy#invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("目标方法执行前的输出。");
Object proxyObj = method.invoke(realService, args);
System.out.println("目标方法执行后的输出。"); return proxyObj;
}
大概就这样吧~ 欢迎交流学习!
转载自:https://juejin.cn/post/7422548463235153930