代理模式简单入门

一 什么是代理模式(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版本代码的问题

  1. 性能计数器代码侵入到业务代码中,跟业务代码耦合;
  2. 业务代码职责不单一

考虑将框架代码与业务代码解耦,此时可以使用代理模式

三 如何使用代理模式(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

静态代理的问题

  1. 代理类需要将原始代码中的类都实现一遍,导致类的数量成倍增加
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服务,缓存等等,也可以用代理模式实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值