目录
JAVA中动态代理分为两种,JDK动态代理和cglib的动态代理。
JDK动态代理
JDK代理只能对实现接口的类生成代理;在运行时利用反射机制生成一个实现代理接口的匿名类,这样代理类和被代理类就拥有了同样的接口方法,在调用具体方法时通过委托InvokeHandler调用invoke()方法来调用被代理类的方法。
Proxy类
java.lang.reflect包下的Proxy类是用于创建代理类,该类的 newProxyInstance() 方法可以来创建Proxy类,动态生成的代理类会继承Proxy这个类。
InvocationHandler接口
这个接口是动态代理类实现代理功能的关键,需要实现代理的被代理类都要创建一个实现了InvocationHandler接口的实例类,重写这个接口的invoke() 方法。invoke() 方法的作用是基于反射机制实现对被代理类的方法的调用。
JDK动态代理步骤
- 获取 被代理类 上的所有接口列表;
- 确定要生成的代理类的类名,默认为:
com.sun.proxy.$ProxyXXXX
;- 根据需要实现的接口信息,在代码中动态创建 该 Proxy 类的字节码;
- 将对应的字节码转换为对应的 class 对象;
- 创建被代理类对应的
InvocationHandler
实例 (用来处理Proxy
所有方法调用);- 调用Proxy的newProxyInstance() 方法,以
InvocationHandler
实例对象为参数,实例化一个被代理类的proxy对象。
JDK动态代理代码示例
被代理类的接口
public interface Subject {
public String SayHello(String name);
public String SayGoodBye();
}
被代理类
public class RealSubject implements Subject {
public String SayHello(String name){
return "hello " + name;
}
public String SayGoodBye(){
return " good bye ";
}
}
被代理类对应的InvocationHandler接口实例
/**
* 调用处理器实现类
* 每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象
*/
public class InvocationHandlerImpl implements InvocationHandler {
/** 这个就是我们要代理的真实对象*/
private Object subject;
/** 构造方法,给我们要代理的真实对象赋初值
* @param subject
*/
public InvocationHandlerImpl(Object subject) {
this.subject = subject;
}
/**
* 该方法负责集中处理动态代理类上的所有方法调用。
* 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
* @param proxy 代理类实例
* @param method 被调用的方法对象
* @param args 调用参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
Object returnValue = method.invoke(subject, args);
return returnValue;
}
}
JDK动态代理类是如何调用被代理类的方法的
基于以上示例和代理类生产的步骤,JDK生成的最终的代理类是一个继承自Proxy并实现了我们定义的Subject接口的代理类,在代理类实现的Subject接口方法的内部,通过托InvocationHandlerImpl的invoke通过反射机制调用真实被代理类的同名方法实现代理调用的目的。
public final class ProxySubject extends Proxy implements Subject {
private static Method m1;
private static Method m4;
private static Method m3;
private static Method m2;
private static Method m0;
public ProxySubject(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 SayGoodBye() throws {
try {
return (String)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String SayHello(String var1) throws {
try {
return (String)super.h.invoke(this, m3, 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 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"));
m4 = Class.forName("fk.Subject").getMethod("SayGoodBye");
m3 = Class.forName("fk.Subject").getMethod("SayHello", Class.forName("java.lang.String"));
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());
}
}
}