设计模式-结构型-代理模式
结构型模式主要总结了一些类和对象组合在一起的经典结构,这些经典的结构可以解决特定应用场景的问题。结构型模式包括:
- 代理模式
- 桥接模式
- 装饰器模式
- 适配器模式
- 门面模式
- 组合模式
- 享元模式
1. 代理模式原理解析
- 代理模式 Proxy Design Pattern
- 在不改变原始类(被代理类)代码的情况下,通过引入代理类来给原始类附加功能
下述是实现MetricsCollector的初始想法
框架代码和业务代码耦合度太高,后期维护或者框架的更换代价都会很大
业务类职责最好单一,只聚焦业务处理
// Original idea for metricsCollector
public class UserController {
//…省略其他属性和方法…
private MetricsCollector metricsCollector; // 依赖注入public UserVo login(String telephone, String password) {
long startTimestamp = System.currentTimeMillis();// … 省略login逻辑…
long endTimeStamp = System.currentTimeMillis();
long responseTime = endTimeStamp - startTimestamp;
RequestInfo requestInfo = new RequestInfo(“login”, responseTime, startTimestamp);
metricsCollector.recordRequest(requestInfo);//…返回UserVo数据…
}public UserVo register(String telephone, String password) {
long startTimestamp = System.currentTimeMillis();// … 省略register逻辑…
long endTimeStamp = System.currentTimeMillis();
long responseTime = endTimeStamp - startTimestamp;
RequestInfo requestInfo = new RequestInfo(“register”, responseTime, startTimestamp);
metricsCollector.recordRequest(requestInfo);//…返回UserVo数据…
}
}
- 构建代理类UserControllerProxy
- 代理类UserCOntrollerProxy和原始类UserController实现相同的接口IUserController。UserController只负责业务功能,代理类UserControllerProxy负责在业务代码执行前后附加其他逻辑代码,并通过委托的方式来调用原始类执行业务代码。
public interface IUserController {
UserVo login(String telephone, String password);
UserVo register(String telephone, String password);
}
public class UserController implements IUserController {
//...省略其他属性和方法...
@Override
public UserVo login(String telephone, String password) {
//...省略login逻辑...
//...返回UserVo数据...
}
@Override
public UserVo register(String telephone, String password) {
//...省略register逻辑...
//...返回UserVo数据...
}
}
public class UserControllerProxy implements IUserController {
private MetricsCollector metricsCollector;
private UserController userController;
public UserControllerProxy(UserController userController) {
this.userController = userController;
this.metricsCollector = new MetricsCollector();
}
@Override
public UserVo login(String telephone, String password) {
long startTimestamp = System.currentTimeMillis();
// 委托
UserVo userVo = userController.login(telephone, password);
long endTimeStamp = System.currentTimeMillis();
long responseTime = endTimeStamp - startTimestamp;
RequestInfo requestInfo = new RequestInfo("login", responseTime, startTimestamp);
metricsCollector.recordRequest(requestInfo);
return userVo;
}
@Override
public UserVo register(String telephone, String password) {
long startTimestamp = System.currentTimeMillis();
UserVo userVo = userController.register(telephone, password);
long endTimeStamp = System.currentTimeMillis();
long responseTime = endTimeStamp - startTimestamp;
RequestInfo requestInfo = new RequestInfo("register", responseTime, startTimestamp);
metricsCollector.recordRequest(requestInfo);
return userVo;
}
}
//UserControllerProxy使用举例
//因为原始类和代理类实现相同的接口,是基于接口而非实现编程
//将UserController类对象替换为UserControllerProxy类对象,不需要改动太多代码
IUserController userController = new UserControllerProxy(new UserController());
- 面对原始类无接口,或者属于其他service无法做改动的时候,可以直接通过继承,来对其进行扩展
public class UserControllerProxy extends UserController {
private MetricsCollector metricsCollector;
public UserControllerProxy() {
this.metricsCollector = new MetricsCollector();
}
public UserVo login(String telephone, String password) {
long startTimestamp = System.currentTimeMillis();
UserVo userVo = super.login(telephone, password);
long endTimeStamp = System.currentTimeMillis();
long responseTime = endTimeStamp - startTimestamp;
RequestInfo requestInfo = new RequestInfo("login", responseTime, startTimestamp);
metricsCollector.recordRequest(requestInfo);
return userVo;
}
public UserVo register(String telephone, String password) {
long startTimestamp = System.currentTimeMillis();
UserVo userVo = super.register(telephone, password);
long endTimeStamp = System.currentTimeMillis();
long responseTime = endTimeStamp - startTimestamp;
RequestInfo requestInfo = new RequestInfo("register", responseTime, startTimestamp);
metricsCollector.recordRequest(requestInfo);
return userVo;
}
}
//UserControllerProxy使用举例
UserController userController = new UserControllerProxy();
2. 动态代理原理解析
代理类的实现需要将原始类当中的所有方法都实现一遍,并加上你需要的代码逻辑,这样做会创建大量的代理类,很麻烦。因此我们需要使用动态代理来解决这个问题,即我们不事先为每个原始类编写代理类,而是在运行的时候,动态的创建原始类对应的代理类,然后在系统当中用代理类替换掉原始类。
Java本身用反射语法来实现动态代理。
public class MetricsCollectorProxy {
private MetricsCollector metricsCollector;
public MetricsCollectorProxy() {
this.metricsCollector = new MetricsCollector();
}
public Object createProxy(Object proxiedObject) {
Class<?>[] interfaces = proxiedObject.getClass().getInterfaces();
DynamicProxyHandler handler = new DynamicProxyHandler(proxiedObject);
return Proxy.newProxyInstance(proxiedObject.getClass().getClassLoader(), interfaces, handler);
}
private class DynamicProxyHandler implements InvocationHandler {
private Object proxiedObject;
public DynamicProxyHandler(Object proxiedObject) {
this.proxiedObject = proxiedObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTimestamp = System.currentTimeMillis();
Object result = method.invoke(proxiedObject, args);
long endTimeStamp = System.currentTimeMillis();
long responseTime = endTimeStamp - startTimestamp;
String apiName = proxiedObject.getClass().getName() + ":" + method.getName();
RequestInfo requestInfo = new RequestInfo(apiName, responseTime, startTimestamp);
metricsCollector.recordRequest(requestInfo);
return result;
}
}
}
//MetricsCollectorProxy使用举例
MetricsCollectorProxy proxy = new MetricsCollectorProxy();
IUserController userController = (IUserController) proxy.createProxy(new UserController());
InvocationHandler
- java的标准接口
创建Proxy 实例
- Proxy.newProxyInstance(classLoader, class, handlerClass)
Spring的AOP的实现原理就是基于动态代理。用户配置好需要给哪些类创建代理,并定义好在执行原始类的业务代码前后执行哪些附加功能、Spring为这些类创建动态代理对象,并且在JVM中替代原始类对象。通过这种方式,实现了给原始类添加附加功能的目的。
3. 代理模式的应用场景
业务系统中的非功能性需求的开发
- 监控
- 统计
- 鉴权
- 限流
- 事务
- 幂等
- 日志
在RPC,缓存中的应用
- RPC将网络通信,数据编解码的细节隐藏起来
- AOP切面完成接口缓存的功能
Reference
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 stone2paul@gmail.com
文章标题:设计模式-结构型-代理模式
文章字数:1.2k
本文作者:Leilei Chen
发布时间:2020-06-20, 03:27:01
最后更新:2020-06-20, 03:27:54
原始链接:https://www.llchen60.com/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E7%BB%93%E6%9E%84%E5%9E%8B-%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。