zoukankan      html  css  js  c++  java
  • 设计模式之美学习-结构型-代理模式(十九)

    什么是代理模式

    在不侵入原有业务逻辑的情况下,实现功能的扩展和增强

    注:静态代理和装饰者模式非常像,个人理解应该是语义上的区别,代理侧重重于控制:比如限流 权限控制 而装饰者只是功能增强

    源码中使用到的代理模式

    《dubbo源码阅读-服务暴露(七)之本地暴露(Injvm》

    《dubbo源码阅读-ProxyFactory(十一)之StubProxyFactoryWrapper本地存根》

    《dubbo源码阅读-服务订阅(九)之Filter实现原理(dubbo)》

    静态代理

    接口代理

    1.被代理类

    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数据...
      }
    }

    2.代理增强

    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());

    增加记录耗时的方法

    类代理

    对于这种外部类的扩展,我们一般都是采用继承的方式

    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();

    java动态代理

    手动代理的缺点 就是要将被代理的类的方法都实现一遍 比如上面增加记时的功能  导致大量的模板代码,增加了开发量和维护难度 如果是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());

    cglib代理

    什么是cglib

    CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。我们知道Java中有一个动态代理也是做这个事情的,那我们为什么不直接使用Java动态代理,而要使用CGLIB呢?答案是CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了

    简单是使用

    1.引入POM

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2.2</version>
    </dependency>

    2.main

    public class SampleClass {
        public void test(){
            System.out.println("hello world");
        }
     
        public static void main(String[] args) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(SampleClass.class);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    System.out.println("before method run...");
                    Object result = proxy.invokeSuper(obj, args);
                    System.out.println("after method run...");
                    return result;
                }
            });
            SampleClass sample = (SampleClass) enhancer.create();
            sample.test();
        }
  • 相关阅读:
    164 Maximum Gap 最大间距
    162 Find Peak Element 寻找峰值
    160 Intersection of Two Linked Lists 相交链表
    155 Min Stack 最小栈
    154 Find Minimum in Rotated Sorted Array II
    153 Find Minimum in Rotated Sorted Array 旋转数组的最小值
    152 Maximum Product Subarray 乘积最大子序列
    151 Reverse Words in a String 翻转字符串里的单词
    bzoj3994: [SDOI2015]约数个数和
    bzoj 4590: [Shoi2015]自动刷题机
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12566891.html
Copyright © 2011-2022 走看看