在不改变原始类(或叫被代理类)的情况下,通过引入代理类来给原始类附加功能
一般情况下,让代理类和原始类实现同样的接口。
如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的。可以让代理类继承原始类的方法来实现代理模式。
原理解析
给controller加入性能计数器功能
普通写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class UserController { //...省略其他属性和方法... private MetricsCollector metricsCollector; // 依赖注入
public UserVo login(String telephone, String password) { long startTimestamp = System.currentTimeMillis(); // login逻辑 long endTimeStamp = System.currentTimeMillis();
RequestInfo requestInfo = new RequestInfo("login", endTimeStamp - startTimestamp, startTimestamp); metricsCollector.recordRequest(requestInfo); return UserVo; } }
|
代理模式-接口实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| 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) { //... }
}
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(); RequestInfo requestInfo = new RequestInfo("login", endTimeStamp - startTimestamp, startTimestamp); metricsCollector.recordRequest(requestInfo); return userVo; } }
//UserControllerProxy使用举例 //因为原始类和代理类实现相同的接口,是基于接口而非实现编程 //将UserController类对象替换为UserControllerProxy类对象,不需要改动太多代码 IUserController userController = new UserControllerProxy(new UserController());
|
代理模式-继承实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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(); RequestInfo requestInfo = new RequestInfo("login", endTimeStamp - startTimestamp, startTimestamp); metricsCollector.recordRequest(requestInfo); return userVo; } } //UserControllerProxy使用举例 UserController userController = new UserControllerProxy();
|
动态代理原理解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| 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();
String apiName = proxiedObject.getClass().getName() + ":" + method.getName(); RequestInfo requestInfo = new RequestInfo(apiName, endTimeStamp - startTimestamp, startTimestamp); metricsCollector.recordRequest(requestInfo); return result; } } }
//应用 MetricsCollectorProxy proxy = new MetricsCollectorProxy(); IUserController userController = (IUserController) proxy.createProxy(new UserController());
|
应用
代理模式在RPC、缓存中的应用
其他应用:监控、统计、鉴权、限流、事务、幂等、日志。
缓存
需求:开发一个有缓存功能接口,对于某些接口请求,如果入参相同,在设定的过期时间内,直接返回缓存结果