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();
        }
  • 相关阅读:
    day50——前端简介、标签分类、常用标签
    day46——约束条件、表与表建 关系、修改表的完整语法
    day45——存储引擎、数据类型、约束条件
    day44——存储数据的发展、数据库分类、mysql
    Ⅰ:计算机核心基础
    Ⅶ:基本数据类型及内置方法
    Ⅶ:作业
    Ⅵ:深浅copy
    Ⅵ:流程控制
    Ⅳ:运算符
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12566891.html
Copyright © 2011-2022 走看看