在静态代理中,真实对象和代理角色是“一对一”的关系。而在动态代理中,真实对象和代理角色是“多对一”的关系。动态代理可以用一个“万能”的代理者来代理任何类型的真实对象,而不用像静态代理那样给每个真实角色都设置一个代理,这也是动态代理的最大优势。
静态代理需要实现和真实对象相同的接口。例如,房屋中介和真正房屋的主人,都需要“出租房”,因此“出租房”就是两者需要共同实现的接口。但是,动态代理既然是一个“万能”的代理者,那么动态代理应该实现什么接口呢?例如,房屋主人和汽车主人,都需要动态代理,那么这个动态代理应该实现“出租房”还是“出租车”的接口呢?为了解决这个问题,JDK 提供了一个“万能”的动态代理接口——InvocationHandler,及使用动态代理时可用 InvocationHandler 接口中的 invoke() 方法代理出租房、出租车等各种业务方法。
package dynamicproxy;
// 租房接口
public interface Subject {
boolean rent(int money);
}
package dynamicproxy;
// 出租车接口
public interface Subject2 {
boolean rentCar(String type);
}
package dynamicproxy;
// 租房真实角色
public class RealSubject implements Subject {
@Override
public boolean rent(int money) {
System.out.println("租房" + money + "元");
return true;
}
}
package dynamicproxy;
// 租车真实接口
public class RealSubject2 implements Subject2 {
@Override
public boolean rentCar(String type) {
System.out.println("租用的车类型:" + type);
return true;
}
}
package dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @className: DynamicProxy
* @description: 动态代理角色
* @date: 2022/5/10
* @author: cakin
*/
public class DynamicProxy implements InvocationHandler {
private Object obj; // 可以代理任意 类型的角色
public DynamicProxy(Object obj) {
this.obj = obj;
}
public void before() {
System.out.println("before rent()...");
}
/**
* 功能描述:真正被代理的方法的返回值
*
* @param proxy 代理的角色
* @param method 被代理的方法
* @param args 方法的参数
* @return Object
* @author cakin
* @date 2022/5/10
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.before();
// obj.method(args)
boolean result = (boolean) (method.invoke(obj, args)); // 通过反射调用rent()方法
this.after();
return result;
}
public void after() {
System.out.println("after...");
}
}
package dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
// 真实对象
Subject realSubject = new RealSubject();
// 初步的代理对象:handler 就是真实角色 realSubject 的初步代理对象
InvocationHandler handler = new DynamicProxy(realSubject);
// 最终的代理对象
/*
* newProxyInstance(a,b,c) ;
* a:初步代理对象的类加载器
* b:接口类型的数组。要代理的方法是在哪些接口中定义的,即 realSubject 的接口;因为语法上允许一个类实现多个接口,因此接口是一个数组
* c:要将哪一个 初步代理对象 转成最终代理对象
*/
Subject subProxy = (Subject) Proxy.newProxyInstance(
handler.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
handler);
boolean result = subProxy.rent(3000); // 会调用动态代理对象的 invoke()
System.out.println(subProxy.getClass().getName());
System.out.println(result ? "ok" : "error");
}
}
package dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test2 {
public static void main(String[] args) {
Subject2 realSubject2 = new RealSubject2();
InvocationHandler handler2 = new DynamicProxy(realSubject2);
Subject2 subProxy2 = (Subject2) Proxy.newProxyInstance(
handler2.getClass().getClassLoader(),
realSubject2.getClass().getInterfaces(),
handler2);
subProxy2.rentCar("宝马");
}
}
before rent()...
租房3000元
after...
com.sun.proxy.$Proxy0
ok
before rent()...
租用的车类型:宝马
after...
1 编写自定义接口。接口本身包含了真实角色中的方法(称为方法A)。
2 编写真实角色类。真实角色类需要实现自定义接口,并重写接口中的方法A。
3 编写动态代理角色类。动态代理角色类实现 InvocationHandler 接口,并重写接口中的 invoke() 方法,再通过 method.invoke(obj,args)调用真实角色中的方法A。
4 使用时,先根据真实角色,产生一个初步代理角色 handler,即 handler = new DynamicProxy(真实角色);再通过 subProxy = (自定义接口) Proxy.newProxyInstance(类加载器,真正角色接口数组,初步代理角色)产生一个最终的代理对象 subProxy;最后通过 subProxy 调用真实角色方法 A,但实际上,在调用代理角色方法的 invoke() 方法。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/chengqiuming/article/details/124698456
内容来源于网络,如有侵权,请联系作者删除!