05-代理模式

05-代理模式

01.基于接口实现代理模式

  1. 性能统计代码和业务代码在一起存在的问题。
/**
 * 如下在登录代码中收集性能数据存在两个问题:
 *  1 性能统计代码侵入业务代码。
 *  2 性能统计的代码与业务代码无关,业务代码最好只聚焦业务处理。
 */
public class UserController implements IUserController {

    @Override
    public boolean login(String phone, String password) {
        long start = System.currentTimeMillis();
        // 登录的业务操作

        long end = System.currentTimeMillis();
        System.out.println("登录用时 " + (end - start));

        return false;
    }
}
  1. 基础接口实现代理模式。
// 接口
public interface IUserController {

    boolean login(String phone, String password);
}

// 真正处理业务的类
public class UserController implements IUserController {

    @Override
    public boolean login(String phone, String password) {
        // 登录的业务操作
        return false;
    }
}

// 代理类
public class UserControllerProxy implements IUserController {

    private final IUserController userController;
    public UserControllerProxy(IUserController userController) {
        this.userController = userController;
    }

    @Override
    public boolean login(String phone, String password) {
        long start = System.currentTimeMillis();
        boolean login = userController.login(phone, password);
        long end = System.currentTimeMillis();
        System.out.println("登录执行时间 " + (end - start));
        return login;
    }
}

// 代理类使用方式。
UserControllerProxy proxy = new UserControllerProxy(new UserController());

02.基于继承实现代理模式

  1. 当原始类没有定义接口,并且原始类来自第三方类库,即不能给原始类添加接口,那么就需要使用继承的方式实现代理模式。

  2. 继承实现代理模式。

public class UserController {
    
    public boolean login(String phone, String password) {
        // 登录的业务操作
        return false;
    }
}

public class UserControllerProxy extends UserController {

    @Override
    public boolean login(String phone, String password) {
        long start = System.currentTimeMillis();
        boolean login = super.login(phone, password);
        long end = System.currentTimeMillis();
        System.out.println("登录时间 " + (end - start));
        return login;
    }
}

UserControllerProxy proxy = new UserControllerProxy();

03.基于反射实现代理模式

  1. 基于接口实现代理模式和基于继承实现代理模式也叫作静态代理;基于反射实现代理模式也成为动态代理。
  2. 对于添加性能统计的功能,静态代理需要将所有的代码重新实现一遍,如果有较多的方法都需要添加附加功能时,就会产生过去的重复代码,导致代码难以维护。
  3. 基于反射实现代理模式。
public interface IUserController {

    boolean login(String phone, String password);
}

public class UserController implements IUserController {

    @Override
    public boolean login(String phone, String password) {
        // 登录的业务操作
        return false;
    }
}

public class MetricsControllerProxy {

    private Object createProxy(Object proxyObject) {
        Class<?>[] interfaces = proxyObject.getClass().getInterfaces();
        DynamicProxyHandler handler = new DynamicProxyHandler(proxyObject);
        return Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(), interfaces, handler);
    }

    private static class DynamicProxyHandler implements InvocationHandler {

        private final Object proxyObject;
        public DynamicProxyHandler(Object proxyObject) {
            this.proxyObject = proxyObject;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            long start = System.currentTimeMillis();
            Object result = method.invoke(proxyObject, args);
            long end = System.currentTimeMillis();
            System.out.println("执行时间 " + (end - start));
            return result;
        }
    }
}

// 1 代理类会对UserController中的所有的方法添加性能统计功能。
// 2 如果其他的类也需要增加性能统计功能,只需要通过proxy.createProxy(xxx)代理即可。
MetricsControllerProxy proxy = new MetricsControllerProxy();
IUserController userController = (IUserController) proxy.createProxy(new UserController());
userController.login("phone", "password");

04.代理模式总结

  1. 代理模式的描述:在不改变原始类的情况下,通过代理类来给原始类附加不相关的其他功能。
  2. 对于静态代理,一般使用基于接口的静态代理。当原始类没有定义接口并无法直接为其添加接口时,可以使用基于继承的静态代理。
  3. 当有多个类或者多个方法都需要附加相同的功能时,可以使用动态代理。
  4. 动态代理又分为JDK动态代理和GCLIB动态代理。JDK动态代理需要原始类定义了接口;GCLIB动态代理用来解决原生类没有定义接口的情况,其本质是通过字节码处理工具ASM来转换字节码并生成新类。
  5. 代理模式可以应用在开发一些非业务需要上,如监控、统计、权限、限流、事务和日志;代理模式也可以应用在PRC和缓存中。
posted @ 2022-11-27 08:47  行稳致远方  阅读(30)  评论(0)    收藏  举报