动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
委托接口
public interface DSubject {
public String invokeMethod(String argument);
}
委托接口实现类
public class DRealSubject implements DSubject{
@Override
public String invokeMethod(String argument) {
int i = 0;
for(int j = 0; j < 100000000; j++){
i++;
}
return "success";
}
}
动态代理类
public class DSubjectInvocationHandler implements java.lang.reflect.InvocationHandler{
private Object delegate;
public DSubjectInvocationHandler(Object delegate) {
this.delegate = Objects.requireNonNull(delegate, "delegate must not be null.");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
Object returnObject = method.invoke(delegate, args);
long finish = System.currentTimeMillis();
String strString =
String.format("Object:%s,method:%s,argument:%s,cost(ms):%d,result:%s",
delegate.getClass().getSimpleName(), method.getName(), Arrays.toString(args), finish - start, returnObject);
System.out.println(strString);
return returnObject;
}
}
测试
public class ProxyTest {
public static void main(String[] args){
DSubject delegate = new DRealSubject();
java.lang.reflect.InvocationHandler invocationHandler = new DSubjectInvocationHandler(delegate);
DSubject proxy = (DSubject) java.lang.reflect.Proxy.newProxyInstance(
delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(),
invocationHandler);
proxy.invokeMethod("gogo");
}
}
结果:
Object:DRealSubject,method:invokeMethod,argument:[gogo],cost(ms):1,result:success
通过上面测试例子,代理对象是通过Proxy.newProxyInstance()方法生成的,通过深入JDK的源码,其实,Proxy.newProxyInstance()是通过动态生成代理类的字节码,再由字节码反射成代理对象的,动态生成代理类的字节码,由下面方法生成:
byte[] sun.misc.ProxyGenerator.generateProxyClass(proxyName, Class<?>[] interfaces);//生成代理类字节码
动态生成代理类字节后,可通过类加载器的defineClass()方法加载类,当然下面ProxyClassLoader类是我自己测试写的,不是JDK的类。
private static class ProxyClassLoader extends ClassLoader{
/**
* @param name The expected binary name of the class, or null if not known
* @param b The bytes that make up the class data. The bytes in positions off
* through off+len-1 should have the format of a valid class file as
* defined by The Java™ Virtual Machine Specification.
* @param off The start offset in b of the class data
* @param len The length of the class data
* @return
*/
public Class<?> defineClass0(String name, byte[] b, int off, int len){
return super.defineClass(name, b, off, len);
}
}
加载得到类后,便可以通过反射方式生成类的对象。
代理类的构造方法需要传入一个InvocationHandler对象,也既是我们上面定义的DSubjectInvocationHandler类的对象,而InvocationHandler对象的构造函数则传入了委托接口的真实实现类DRealSubject,则在调用代理类对象时,也会通过反射的方式,调用委托接口的相关方法,其实生成的代理类对象结构如下:
public class DSubject$Proxy1 extends java.lang.reflect.Proxy implements DSubject{
private static Method equalsMethod;
private static Method hashCodeMethod;
private static Method toStringMethod;
private static Method invokeMethod;
static{
try {
equalsMethod = Class.forName("java.lang.Object").getMethod("equals", new Class<?>[]{Class.forName("java.lang.Object")});
hashCodeMethod = Class.forName("java.lang.Object").getMethod("hashCode", new Class<?>[0]);
toStringMethod = Class.forName("java.lang.Object").getMethod("toString", new Class<?>[0]);
invokeMethod = Class.forName("lam.design.pattern.proxy.dynamic.DSubject")
.getMethod("invokeMethod", new Class<?>[]{Class.forName("java.lang.String")});
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public DSubject$Proxy1(InvocationHandler h) {
super(h);
}
@Override
public String invokeMethod(String argument) {
try {
return (String)h.invoke(this, invokeMethod, new Object[]{argument});
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public final boolean equals(Object obj) {
try {
return ((Boolean)h.invoke(this, equalsMethod, new Object[]{obj})).booleanValue();
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public final int hashCode() {
try {
return ((Integer)h.invoke(this, hashCodeMethod, null)).intValue();
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public final String toString() {
try {
return (String)h.invoke(this, toStringMethod, null);
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
}
动态代理是设计模式-代理模式的一种
代理模式包含:静态代理和动态代理
代理模式可以参照点击打开链接