代理设计模式(Proxy Design Pattern)

115 阅读2分钟

参考资料

image.png

应用场景

  • 在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。将这些附加功能与业务功能解耦,放到代理类中统一处理,让程序员只需要关注业务方面的开发。
  • RPC通过远程代理,将网络通信、数据编解码等细节隐藏起来。客户端在使用 RPC 服务的时候,就像使用本地函数一样,无需了解跟服务器交互的细节。
  • 动态代理,基于不同情况,进行不同的调用

代理模式的实现方式

实现接口的方式

public interface IUser{
	UserVo login(String telephone, String password);
}
public class User implements IUser{
	@Override
	public UserVo login(String telephone, String password){
		//省略login逻辑
	}
}
public class UserProxy implements IUser{
	private User user;
	//构造方法注入
	public UserProxy(User user){
		this.user = user;
	}
		
	@Override
	public UserVo login(String telephone, String password){
		//增强
		long startTime = System.currentTimeMillis();
		//原始
		UserVo userVo = user.login(telephone, password);
		//增强
		long endTime = System.currentTimeMillis();

		return userVo;
	}
}

继承的方式

如果原始的类是来自第三方类库,无法修改,那么一般采用这种继承的方式

public class UserProxy extends IUser{
	private User user;
	//构造方法注入
	public UserProxy(User user){
		this.user = user;
	}
		
	@Override
	public UserVo login(String telephone, String password){
		//增强
		long startTime = System.currentTimeMillis();
		//原始
		UserVo userVo = super.login(telephone, password);
		//增强
		long endTime = System.currentTimeMillis();

		return userVo;
	}
}


动态代理的方式

如果要添加的附加功能的类有不止一个,我们需要针对每个类都创建一个代理类,代码臃肿。

JDK动态代理

public interface Happy {
    // 协议
    void happy();
}
public class JinLian implements Happy {
    // 被代理类
    public void happy(){
        System.out.println("金莲在happy...");
    }
}
public class Test {
    public static void main(String[] args) {
    
          
    //static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象
	//参数1ClassLoader: 被代理类的类加载器
	//参数2interfaces:  被代理类实现的所有接口的字节码对象
    //参数3InvocationHandler: 执行处理接口
    //返回: 代理对象
    //参数1和参数2是用来帮助生成对应的代理对象,参数3用来监听代理对象调用方法,帮助我们调用方法

    //InvocationHandler接口:
    //Object invoke(Object proxy, Method method, Object[] args)方法:调用代理类的任何方法,此方法都会执行
    //参数1proxy: 代理对象,一般不用,忽略
    //参数2method: 代理对象调用的方法
	//参数3args: 代理对象调用方法传入的实际参数
    //返回值:当前方法执行的返回值
         
        JinLian jl = new JinLian();

        // 获取金莲的代理对象
        Happy proxy = (Happy)Proxy.newProxyInstance(JinLian.class.getClassLoader(), JinLian.class.getInterfaces(), new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 代理对象调用方法就会执行invoke方法
                System.out.println("以做衣服的名义,帮2人开好房间...");
                // 金莲happy
                method.invoke(jl);
                System.out.println("打扫战场...");
                return null;
            }
        });
        // 代理对象调用happy方法
        proxy.happy();// void happy();
    }
}