1. 代理模式简介分类

    • 概念

      ​ 代理,是为了在不修改目标对象的基础上,增强目标方法的业务逻辑。

      ​ 客户类需要执行的是目标对象的目标方法,但是真正执行的是代理对象的代理方法,客户类对目标对象的访问是通过代理对象来实现的。当然,代理类与目标类需要实现同一个接口。

    • 举例

      生活中遇到了官司,我们平常老百姓对法律的了解不全面,所以一般都会请律师处理。

      目标对象:法庭上我们一般称为当事人即目标对象

      代理类:律师称为代理律师即代理类

      共同接口:都为了一个共同的目标努力赢得官司即为共同接口

      目标方法:我们所做的提供证据各种努力成为目标方法

      代理方法:再此过程中我们可能做不全面,律师对证据材料等进行整理收集,结合法律法规进行辩证等等,此过程称为代理方法

    • 代理分类

      代理模式一般分为静态代理与动态代理,动态代理又分为JDK动态代理与CGLIB动态代理

  2. 静态代理

    • 概念

      静态代理是指,代理类在程序运行前就已经定义好,其与目标类等关系在程序运行前就已经确立。

      静态代理类似于富翁于私人律师的代理关系,并不是在发生官司之后才去请律师,而是在此之前已经确立好的代理关系。

    • 实现与解析

      a、定义业务接口

      package com.rangers.proxy.staticProxy;
      
      /**
      * @Author Rangers
      * @Description
      * @Date 2021-03-09
      **/
      public interface IAccountService {
      // 转账业务接口
      void transfer();
      }

      b、定义目标类与目标方法

      package com.rangers.proxy.staticProxy;
      
      /**
      * @Author Rangers
      * @Description
      * @Date 2021-03-09
      **/
      public class AccountServiceImpl implements IAccountService {
      // 转账业务实现即目标方法
      @Override
      public void transfer() {
      System.out.println("进行转账操作");
      }
      }

      c、定义代理类AccountServiceImplProxy,实现IAccountService接口。在有参构造方法中传入目标对象,将目标对象引入代理类,以便代理类调用目标方法,进行增强

      package com.rangers.proxy.staticProxy;
      
      /**
      * @Author Rangers
      * @Description
      * @Date 2021-03-09
      **/
      public class AccountServiceImplProxy implements IAccountService { // 声明目标接口对象
      private IAccountService target; public AccountServiceImplProxy() {
      }
      // 业务接口对象作为构造器,用于接收目标对象
      public AccountServiceImplProxy(IAccountService target) {
      this.target = target;
      } @Override
      public void transfer() {
      // 此处对目标方法进行增强
      System.out.println("对转账人身份校验。。");
      target.transfer();
      System.out.println("进行日志记录。。");
      }
      }

      d、编写测试类TransferServiceTest

      package com.rangers.proxy.staticProxy;
      
      /**
      * @Author Rangers
      * @Description
      * @Date 2021-03-09
      **/
      public class TransferServiceTest {
      public static void main(String[] args) {
      // 创建目标对象
      IAccountService target = new AccountServiceImpl();
      // 创建代理对象,传入目标对象进行初始化
      IAccountService proxy = new AccountServiceImplProxy(target);
      // 执行代理对象的方法
      proxy.transfer();
      }
      }
  3. 动态代理

    ​ 动态代理,程序在整个运行过程中根本就不存在目标类的代理类,目标对象的代理对象只是由代理工具在程序运行时由JVM根据反射等机制动态生成。代理对象与目标对象的代理关系在程序运行时才确立。

    ​ 动态代理类似于普通人在有官司之后,再聘请律师的,即代理关系是在官司发生后确立的。

    ​ 动态代理的实现方式有两种:JDK的动态代理、CGLIB动态代理

    a、JDK动态代理

    • 概念

      ​ JDK动态代理是通过JDK提供的 java.lang.reflect.Proxy类实现动态大力,使用其静态方法newProxyInstance(),对目标对象、业务接口及业务增强逻辑,自动生成一个动态代理对象。

      public static newProxyInstance(ClassLoader classLoader,Class<?> interfaces,InvocationHandler handler)
      classLoader:传入目标类的类加载器,通过目标对象的反射获取
      interfaces:目标对象实现的接口数组,通过目标对象的反射获取
      handler:业务增强逻辑,需要具体实现

      ​ InvocationHandler是个接口,实现InvocationHandler接口的类用于增加目标类的业务逻辑。需要实现invoke()方法,具体的增强逻辑就是在此方法中进行实现,程序调用住业务逻辑时会自动调用invoke()方法

      public Object invoke(Object proxy,Method method,Object[] args)
      proxy:生成的代理对象
      method:目标方法
      args:目标方法的参数

      ​ Method类对象,invoke()方法进行执行目标对象的目标方法

      public Object invoke(Object obj,Object args)
      method.invoke(Object target,Object...args)执行目标方法
      target:目标对象
      args:目标方法的执行参数
    • 实现与解析

      1. 定义业务接口与实现类
      package com.rangers.proxy.jdkProxy;
      
      /**
      * @Author Rangers
      * @Description
      * @Date 2021-03-09
      **/
      public interface IAccountService {
      // 转账业务接口
      void transfer();
      }
      package com.rangers.proxy.jdkProxy;
      
      /**
      * @Author Rangers
      * @Description
      * @Date 2021-03-09
      **/
      public class AccountServiceImpl implements IAccountService {
      // 转账业务实现即目标方法
      @Override
      public void transfer() {
      System.out.println("进行转账操作");
      }
      }
      1. 定义JdkProxy类实现InvocationHandler接口,实现invoke()方法,并对业务逻辑进行增强
      package com.rangers.proxy.jdkProxy;
      
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method; /**
      * @Author Rangers
      * @Description
      * @Date 2021-03-09
      **/
      public class JdkProxy implements InvocationHandler { private Object target; public JdkProxy() {
      } public JdkProxy(Object target) {
      this.target = target;
      } @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      // 此处对目标方法进行增强
      System.out.println("对转账人身份校验。。");
      Object result = method.invoke(target, args);
      System.out.println("进行日志记录。。");
      return result;
      }
      }
      1. 新建测试类JDKProxyTest
      package com.rangers.proxy.jdkProxy;
      
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy; /**
      * @Author Rangers
      * @Description
      * @Date 2021-03-09
      **/
      public class JDKProxyTest {
      public static void main(String[] args) {
      // 创建目标对象
      IAccountService target = new AccountServiceImpl();
      // 创建代理对象,传入目标对象进行初始化
      IAccountService proxyService =
      (IAccountService) Proxy.newProxyInstance(
      target.getClass().getClassLoader(),
      target.getClass().getInterfaces(),
      new JdkProxy(target)
      );
      // 亦可使用匿名类进行实现
      /*(IAccountService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
      target.getClass().getInterfaces(), new InvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      // 此处对目标方法进行增强
      System.out.println("对转账人身份校验。。");
      Object result = method.invoke(target, args);
      System.out.println("进行日志记录。。");
      return result;
      }
      });*/
      // 此处执行的业务方法就是代理对象的增强过的逻辑
      proxyService.transfer();
      }
      }

    注:使用JDK动态代理时需要目标类目标方法必须在实现的接口中,否则不能使用此方式进行动态打击。对于无接口的类需要实现动态代理,就要使用CGLIB方式来进行实现

    b、CGLIB动态代理

    • 概念

      ​ CGLIB是一个开源的第三方代码生成类库,对于无接口的类,要为其创建动态代理,就要使用CGLIB进行实现。CGLIB代理的生成原理是生成目标类的子类,子类是增强过的,就是目标类的代理类。所以,使用CGLIB生成动态代理,要求目标类必须能够被继承,即不能是final修饰的类。

      ​ CGLIB包的底层是通过使用一个小儿快的字节码处理框架ASM(java字节码操控框架),来转换字节码并生成新的类,通过对字节码进行增强来生成代理类。

      ​ 我们静态代理理解为私人律师,JDK动态代理成为代理律师,CGLIB动态代理可以理解为老父亲的儿子。老父亲是被需要增强对目标类,儿子则是用于增强父亲对代理类,事先不需要约定。父亲需要儿子增强什么,儿子就增强什么,即他们之间的关系不要接口来进行约束。

    • 注意要点

      使用CGLIB动态代理时,生成代理类的类需要实现MethodInterceptor接口及intercept()方法

      public Object intercept(Object proxy,Method method,Objectp[] args,MethodProxy methodProxy)
      proxy:代理对象
      method:代理对象的方法,即增强后的方法
      args:方法参数
      methodProxy:代理方法的对象

      创建代理对象时使用Enhancer类

      // 创建增强器
      Enhancer enhancer = new Enhancer();
      // 初始化增强器:将目标类指定为父类
      enhancer.setSuperclass(target.class);
      // 初始化增强器:设置回调至本类中的intercept()方法
      enhancer.setCallback(this);
      // 使用增强器创建代理对象进行返回
      enhancer.create();
    • 实现与解析

      1. 引入CGLIB依赖

            <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib-full</artifactId>
        <version>2.0.2</version>
        </dependency>
      2. 创建目标类AccountService

        package com.rangers.proxy.cglibProxy;
        
        /**
        * @Author Rangers
        * @Description
        * @Date 2021-03-09
        **/
        public class AccountService { // 转账业务 即目标方法
        public void transfer() {
        System.out.println("进行转账操作");
        } // 查询余额 即目标方法
        public void getBalance() {
        System.out.println("查询余额操作");
        }
        }
      3. 创建代理类AccountServiceCglibProxy实现MethodInterceptor接口,完善intercept()方法进行增强,创建生成代理对象createProxy()方法

        package com.rangers.proxy.cglibProxy;
        
        import net.sf.cglib.proxy.Enhancer;
        import net.sf.cglib.proxy.MethodInterceptor;
        import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /**
        * @Author Rangers
        * @Description
        * @Date 2021-03-09
        **/
        public class AccountServiceCglibProxy implements MethodInterceptor { // 声明目标类的成员变量,并创建以目标类为参数的构造器,用于接收目标对象
        private AccountService target; public AccountServiceCglibProxy(AccountService accountService) {
        this.target = accountService;
        } @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 此处对目标方法进行增强
        Object result = new Object();
        if ("transfer".equals(method.getName())){
        System.out.println("对转账人身份校验。。");
        result = method.invoke(target, args);
        System.out.println("进行日志记录。。");
        }else{
        // 直接执行目标对象的目标方法
        result = methodProxy.invokeSuper(target,args);
        }
        return result;
        } // 创建代理对象
        public AccountService createProxy(){
        // 创建增强器
        Enhancer enhancer = new Enhancer();
        // 初始化增强器:将目标类指定为父类
        enhancer.setSuperclass(AccountService.class);
        // 初始化增强器:设置回调至本类中的intercept()方法
        enhancer.setCallback(this);
        // 使用增强器创建代理对象
        return (AccountService) enhancer.create();
        }
        }
      4. 创建测试类CglibProxyTest

        package com.rangers.proxy.cglibProxy;
        
        /**
        * @Author Rangers
        * @Description
        * @Date 2021-03-09
        **/
        public class CglibProxyTest {
        public static void main(String[] args) {
        // 目标对象
        AccountService target = new AccountService();
        // 创建代理对象,传入目标对象进行初始化
        AccountService accountService = new AccountServiceCglibProxy(target).createProxy();
        accountService.transfer();
        accountService.getBalance();
        }
        }

代理模式详解:静态代理、JDK动态代理与Cglib动态代理的更多相关文章

  1. 代理模式详解:静态代理+JDK/CGLIB 动态代理实战

    1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...

  2. Docker Kubernetes Service 网络服务代理模式详解

    Docker Kubernetes  Service 网络服务代理模式详解 Service service是实现kubernetes网络通信的一个服务 主要功能:负载均衡.网络规则分布到具体pod 注 ...

  3. 代理模式之静态代理,JDK动态代理和cglib动态代理

    代理模式,顾名思义,就是通过代理去完成某些功能.比如,你需要购买火车票,不想跑那么远到火车站售票窗口买,可以去附近的火车票代售点买,或者到携程等第三方网站买.这个时候,我们就把火车站叫做目标对象或者委 ...

  4. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  5. java的静态代理、jdk动态代理和cglib动态代理

    Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理.使用代理有两个好处,一是可以隐藏委托类的实现:二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况 ...

  6. Spring 静态代理+JDK动态代理和CGLIB动态代理

    代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ...

  7. 【转】java的动态代理机制详解

    java的动态代理机制详解   在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们 ...

  8. Java代理:静态代理、JDK动态代理和CGLIB动态代理

    代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式.所谓的代理者是指一个类别可以作为其它东西的接口.代理者可以作任何东西的接口:网络连接.存储器中的大对象.文件或其它昂贵或无法复制 ...

  9. [转载] java的动态代理机制详解

    转载自http://www.cnblogs.com/xiaoluo501395377/p/3383130.html 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代 ...

随机推荐

  1. Leetcode(10)-正则表达式匹配

    给定一个字符串 (s) 和一个字符模式 (p).实现支持 '.' 和 '*' 的正则表达式匹配. '.' 匹配任意单个字符. '*' 匹配零个或多个前面的元素. 匹配应该覆盖整个字符串 (s) ,而不 ...

  2. vue-router离开当前页面提示未保存,解决在使用beforeRouteLeave弹窗多次闪现问题

    在使用beforeRouteLeave时要注意两点: 1. next(false)阻止路由继续进行,若不先阻止,会多次执行守卫中的代码 2. 利用setTimeout延时触发弹窗,避免出现闪现情况

  3. JBoss 5.x和6.x 反序列化漏洞(CVE-2017-12149)

    0x01 漏洞简介 该漏洞为 Java反序列化错误类型,存在于 Jboss 的 HttpInvoker 组件中的 ReadOnlyAccessFilter过滤器中.该过滤器在没有进行任何安全检查的情况 ...

  4. 云原生系列2 部署你的第一个k8s应用

    云原生的概念和理论体系非常的完备,but talk is cheap , show me the code ! 但是作为一名程序员,能动手的咱绝对不多BB,虽然talk并不cheap , 能跟不同层次 ...

  5. 网易吃鸡 mac 版,没有声音

    网易吃鸡 mac 版,没有声音 bug 声音太小了 客服电话 问题反馈 提交工单 https://gm.163.com/user_help.html?index=5&stypeid=3619 ...

  6. 蓝湖 UI 设计稿上如何生成渐变色和复制渐变色

    蓝湖 UI 设计稿上如何生成渐变色和复制渐变色 Sketch 生成渐变色 不要上传图片,切图 如果是切图,切图模式下就不会生成 css 代码了 复制渐变色 OK .button { width: 28 ...

  7. How to implement an accurate countdown timer with js

    How to implement an accurate countdown timer with js 如何用 js 实现一个精确的倒计时器 原理剖析 web worker js custom ti ...

  8. Android Studio & zh-Hans

    Android Studio & zh-Hans https://developer.android.com/studio?hl=zh-cn https://developer.android ...

  9. Stack Overflow & Segment Fault

    Stack Overflow & Segment Fault https://stackoverflow.com/ https://stackoverflow.com/users/593446 ...

  10. linux move file / folder bash command

    linux move file / folder bash command mv $ which mv $ man mv # mv [-f] source target/ target folder ...