简介:
代理模式的设计是想要通过一个专门的操作类为一个业务接口服务。
标准代理类代码实现:
interface IMessage{ // 传统代理设计一定要有接口
public void send();
}
class MessageReal implements IMessage{
@Override
public void send() {
System.out.println("【发送一个消息】");
}
}
class MessageProxy implements IMessage{ // 代理类
private IMessage message; // 代理对象,一定是业务接口实例
public MessageProxy(IMessage message) {
this.message = message;
}
public boolean connect(){
System.out.println("【消息代理处理】进行消息发送通道的连接");
return true;
}
public boolean close(){
System.out.println("【消息代理处理】进行消息发送通道的关闭");
return false;
}
@Override
public void send() {
if (this.connect()){ // 如果连接成功
this.message.send(); // 开始发送消息
this.close(); // 发送后关闭
}
}
}
public class MAIN {
public static void main(String[] args) {
IMessage msg = new MessageProxy(new MessageReal());
msg.send();
}
}
输出结果:
以上就是标准代理类的程序实现,但是可以发现在主类中需要获取每一个类和接口的信息才能实现代理类的功能,所以这里最好还是创建一个工厂类进行 对象的获取;
以上是静态代理类的设计,此操作的特点就是:一个代理类为一个接口服务,那么如果现在准备了几千个业务接口,就需要几千个接口,这样合理吗?显然是不合理的,那么就需要进一步进行优化。
动态代理类:
可以发现上面的操作存在大量的重复操作,所以可以进行动态获取信息进行代理类的创建以实现同一的代理操作:
- 不论是动态还是静态的代理类都必须要实现真实业务子类的接收;
- 由于动态代理类不再与某一个接口进行捆绑,应该可以动态获取类的接口信息;
动态代理类的创建要借助于系统类的一个接口:
public interface InvocationHandler;
这个接口中只有一个方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
这个方法在前面的反射经常有见到过。
在进行动态代理设计的时候对于对象的创建都是由JVM底层完成的,此时主要依靠的是java.lang.reflect.Proxy程序类 ,而这个程序类之中只提供有一个核心方法:
代理对象:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
|- ClassLoader loader:获取当前真实主体类的ClassLoader;
|= 一般获取方式为: 业务主体类对象.getClass().getClassLoader()
|- Class<?>[] interfaces:代理都是围绕接口进行的,所以一定要获取真实主体类的接口信息;
|= 一般获取方式为: 业务主体类对象.getClass().getInterfaces()
|- InvocationHandler h:代理处理的方法。
Proxy类的newProxyInstance()方法会根据传入业务接口和实现业务接口的子类创建一个代理对象,代理对象会找到业务接口中的fun()方法,然后使用invoke()去调用实现了业务接口子类中重写的fun()方法;
代码实现:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface IMessage{ // 传统代理设计一定要有接口
public void send();
}
class MessageReal implements IMessage{
@Override
public void send() {
System.out.println("【发送一个消息】");
}
}
class CLMDProxy implements InvocationHandler {
private Object target; // 保存真实业务主体对象
/**
* 进行真实业务对象与代理业务对象之间的绑定处理
* @param target 真实业务对象
* @return Proxy 生成的代理业务对象
*/
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); // 创建代理对象,然后调找到接口方法,由invoke()调用,this就是invoke()方法
}
public boolean connect(){
System.out.println("【消息代理处理】进行消息发送通道的连接");
return true;
}
public boolean close(){
System.out.println("【消息代理处理】进行消息发送通道的关闭");
return false;
}
@Override
public Object invoke(Object pro, Method method, Object[] args) throws Throwable {
System.out.println("*********【执行方法】" + method);
Object returnData = null;
if (this.connect()){ // 连接成功
returnData = method.invoke(this.target, args); // 调用方法
this.close(); // 关闭
}
return returnData;
}
}
public class MAIN {
public static void main(String[] args) {
IMessage msg = (IMessage) new CLMDProxy().bind(new MessageReal()); // 返回的是Object类型,需要向下强制转型
msg.send();
}
}
输出结果:
此时在程序结构中可以发现,newProxyInstance()创建的代理对象是根据传入业务接口子类对象来进行创建的,并不是单一表示某一个接口,这个时候就必须依赖类加载器进行代理对象的伪造。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)