浅谈java动态代理
怎么使用动态代理
共需4个类
- 一个接口和一个实现他的类
package invoke;
public interface ICar {
void run();
}
package invoke;
public class Car implements ICar {
@Override
public void run() {
System.out.println("car run");
}
}
- 一个自定义的InvocationHandler
package invoke;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private final ICar car;
public MyInvocationHandler(ICar car) {
this.car = car;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = method.invoke(car, args);
System.out.println("after");
return result;
}
}
- 一个test main函数
package invoke;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class ProxyDemo {
public static void main(String[] args) {
InvocationHandler invocationHandler = new MyInvocationHandler(new Car());
ICar proxy = (ICar) Proxy.newProxyInstance(Car.class.getClassLoader(),Car.class.getInterfaces() ,invocationHandler);
proxy.run();
}
}
- 运行结果
before
car run
after
Process finished with exit code 0
一些细节
- 开启动态代理生成文件
通过阅读源码需要设置系统变量可以知道只要设置sun.misc.ProxyGenerator.saveGeneratedFiles为true就可以吧动态代理生成的class文件写入文件系统。可以通过在代码中加入一句System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
或者在VMoptions中加入参数-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
来开启这个选项。生成的代理class文件在工程根目录的com\sun\proxy
中 - 反编译代理类
这是我通过idea反编译得到的代理类的结构
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import invoke.ICar;
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 ICar {
private static Method m1;
private static Method m3;
private static Method m2;
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 void run() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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 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"));
m3 = Class.forName("invoke.ICar").getMethod("run");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
研究这个类,发现他通过反射得到了原来 ICar
接口的所有方法,自己也实现了ICar
接口并重写了这几个方法,只不过重写的时候都通过代理来调用各种方法,这里的super.h
变量其实就是MyInvocationHandler
的一个实现,所以最终调用会走到MyInvocationHandler.invoke
的方法实现中。
网友评论