1 静态代理
主题接口
public interface Subject {
void request();
}
真正的主题对象
public class RealSubject implements Subject{
public void request() {
System.out.println("request() 真正的角色");
}
}
代理对象
public class ProxyObject implements Subject {
/**
* 真实对象
*/
private Subject subject;
public ProxyObject(Subject subject){
this.subject = subject;
}
public void request() {
System.out.println("ProxyObject begin");
subject.request();
System.out.println("ProxyObject finish");
}
}
Client
public class Test {
public static void main(String[] args) {
Subject subject = new RealSubject();
ProxyObject proxy = new ProxyObject(subject);
proxy.request();
}
}
打印结果
ProxyObject begin
request() 真正的角色
ProxyObject finish
代理对象中持有一个主题接口的对象。当调用代理对象的request()方法时将会使用主题对象调用主题对象的方法。
2 动态代理
主题
public interface Subject {
void request();
}
主题实现类
public class RealSubject implements Subject{
public void request() {
System.out.println("request() 真正的角色");
}
}
代理者
public class MyIncationHandler implements InvocationHandler{
private Object mTarget;
public MyIncationHandler(Object object){
this.mTarget = object;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("MyIncationHandler before");
Object result = method.invoke(mTarget, args);
System.out.println("MyIncationHandler finish");
return result;
}
}
public class Test {
public static void main(String[] args) {
Subject subject = new RealSubject();
/**
* 第一个参数 classLoader contextLoader
* 第二个参数 接口参数 决定返回的对象实现了哪些接口
* 第三个参数 myIncationHandler 代理时 需要处理具体的接口
*/
MyIncationHandler myIncationHandler = new MyIncationHandler(subject);
Subject proxy = (Subject) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
subject.getClass().getInterfaces(),
myIncationHandler);
proxy.request();
}
}
运行结果
MyIncationHandler before
request() 真正的角色
MyIncationHandler finish
使用代理调用接口里的方法
proxy.request();
最终会回调到实现类的方法,从打印结果可以得出该结论。
并且代理对象中invoke()方法的这一行表示用实现类去反射射调用实现类的方法。
Object result = method.invoke(mTarget, args);
使用动态代理的几个步骤:
1 创建接口,并创建该接口的实现类。
2 创建代理对象实现并实现InvocationHandler接口。在抽象方法中反射调用方法。
3 初始化代理对象
Subject proxy = (Subject) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
subject.getClass().getInterfaces(),
myIncationHandler);
4 用代理对象去调用接口的方法。
proxy.request();
3 动态代理原理
3.1 示例
@Test
public void test_1() {
//1 listenerClazz 实例为 com.sun.proxy.$Proxy4
Class listenerClazz = Proxy.getProxyClass(Listener.class.getClassLoader(), Listener.class);
try {
//2 public com.sun.proxy.$Proxy4(java.lang.reflect.InvocationHandler)
Constructor constructor = listenerClazz.getConstructor(InvocationHandler.class);
try {
//3 通过构造函数来创建对象
Listener proxy = (Listener) constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("new InvocationHandler() invoke --------");
return null;
}
});
//4 通过代理调用方法
proxy.onClick();
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
输出日志
new InvocationHandler() invoke --------
3.2 总结
1 首先通过Proxy.getProxyClass()函数来创建类型为com.sun.proxy.$Proxy4
Class
2 通过com.sun.proxy.$Proxy4
类型的Class来构建Constructor对象
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
Constructor用来标识Proxy的构造函数
3 通过Constructor来创建代理对象com.sun.proxy.$Proxy4
的实例proxy
4 通过proxy调用接口的方法则会调用内部变量InvocationHandler的invoke()函数