一 什么是代理模式(What)
在不改变原始类的情况下,通过继承等方式获取代理类,从而扩展类的功能。
二 什么时候使用代理模式(When)
示例:性能计数器,用以统计某个接口的响应时长、访问时间等等信息。
代码版本 V1
public class UserController{
@Autowired
private MetricsCollector metricsCollector;
public UserVo login(String telephone, String password){
long startTimeStamp = System.currentTimeMills();
//...
long endTimeStamp = System.currentTimeMills();
long responseTime = endTimeStamp - startTimeStamp;
// ...
return userVo;
}
}
V1版本代码的问题
- 性能计数器代码侵入到业务代码中,跟业务代码耦合;
- 业务代码职责不单一
考虑将框架代码与业务代码解耦,此时可以使用代理模式。
三 如何使用代理模式(How)
1 静态代理
示例
public interface IUserService {
/**
* 增加一个用户
*/
void addUser();
/**
* 编辑账户
*/
void editUser();
}
public class UserService implements IUserService{
@Override
public void addUser() {
System.out.println("Add a user ...");
}
@Override
public void editUser() {
System.out.println("Edit a user ...");
}
}
/**
1. 代理类
*/
public class UserServiceProxy implements IUserService{
private UserService userService;
public UserServiceProxy(UserService userService) {
this.userService = userService;
}
@Override
public void addUser() {
long startTime = System.currentTimeMillis();
// 委托
userService.addUser();
long endTime = System.currentTimeMillis();
System.out.println("it takes " + (endTime - startTime) + " ms");
}
@Override
public void editUser() {
long startTime = System.currentTimeMillis();
// 委托
userService.editUser();
long endTime = System.currentTimeMillis();
System.out.println("it takes " + (endTime - startTime) + " ms");
}
}
// 主方法
IUserService userService = new UserServiceProxy(new UserService());
userService.addUser();
userService.editUser();
输出
Add a user ...
it takes 1 ms
Edit a user ...
it takes 0 ms
静态代理的问题
- 代理类需要将原始代码中的类都实现一遍,导致类的数量成倍增加
2 动态代理
说明
代码示例
将静态代理中的代码用动态代理实现
// ProxyHandler
package src.com.lukeye.proxy;
import org.omg.PortableInterceptor.RequestInfo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public 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();
System.out.println(apiName + " takes " + responseTime + " ms");
return result;
}
}
// 代理类
public class DynamicProxy {
public Object createProxy(Object proxiedObject) {
Class<?>[] interfaces = proxiedObject.getClass().getInterfaces();
DynamicProxyHandler handler = new DynamicProxyHandler(proxiedObject);
return Proxy.newProxyInstance(proxiedObject.getClass().getClassLoader(), interfaces, handler);
}
}
// 主方法
DynamicProxy proxy = new DynamicProxy();
IUserService userController = (IUserService) proxy.createProxy(new UserService());
userController.addUser();
userController.editUser();
proxyHandler也可以是代理类的内部类.
输出
Add a user ...
src.com.lukeye.proxy.UserService:addUser takes 0 ms
Edit a user ...
src.com.lukeye.proxy.UserService:editUser takes 0 ms
适用场景
主要用在业务系统的非功能性需求开发,比如:监控、统计、鉴权、限流、事务、幂等、日志,Spring AOP就是基于代理模式实现的。另外,像Pigeon之类的RPC服务,缓存等等,也可以用代理模式实现。