当前位置:

首页 > 编程开发 > Java中动态代理和静态代理的示例分析

Java中动态代理和静态代理的示例分析

0、代理模式为什么要学习代理模式?这是SpringAOP的底层【SpringAOP和SpringMVC】代理模式的分类:静态代理动态代理1、静态代理静态代理中,我们对目标对象的每个方法的增强都是手动完成的(后面会具体演示代码_),非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(_需要对每个目标类都单独写一个代理类)。实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。角色分析:抽象角色:一般会使用接口或者抽象类来解决真实角色:被代理的角色代理角色:代理真实角色,代理真

本文目录

      0、代理模式

      为什么要学习代理模式?这是SpringAOP的底层【SpringAOP和SpringMVC】

      代理模式的分类:

      • 静态代理

      • 动态代理

      1、静态代理

      静态代理中,我们对目标对象的每个方法的增强都是手动完成的(后面会具体演示代码_),非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(_需要对每个目标类都单独写一个代理类)。 实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。

      角色分析:

      • 抽象角色:一般会使用接口或者抽象类来解决

      • 真实角色:被代理的角色

      • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作

      • 客户:访问代理对象的人!

      代码步骤:

      1、接口

      public interface Rent {
          public void rent();
      }

      2、真实角色

      //房东
      public class Host implements Rent {
          public void rent() {
              System.out.println("房东要租房子");
          }
      }

      3、代理角色

      public class Proxy implements Rent{
          private Host host;
          public Proxy() {
          }
          public Proxy(Host host) {
              this.host = host;
          }
          public void rent(){
              seeHouse();
              host.rent();
              fare();
          }
          //看房
          public void seeHouse(){
              System.out.println("中介带你看房");
          }
          //收中介费
          public void fare(){
              System.out.println("中介收费");
          }
      }

      4、客服端访问代理角色

      public class Client {
          public static void main(String[] args) {
              Host host = new Host();
              //代理,代理角色一般会有附属操作!
              Proxy proxy = new Proxy(host);
              proxy.rent();
          }
      }

      代理模式的好处:

      • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务

      • 公共也就交给代理角色!实现业务的分工!

      • 公共业务发生扩展的时候,方便集中管理!

      缺点:

      一个真实角色会产生一个代理角色;从JVM角度来看,静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的class文件。

      2、 加深理解

      AOP,的底层代理模式

      Java中动态代理和静态代理的示例分析

      3、动态代理

      • 动态代理和静态代理角色一样

      • 动态代理的代理类是动态生成的,不是我们直接写好的!

      • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

        • 基于接口——JDK动态代理

        • 基于类:cglib动态代理

        • java字节码实现:javasist

      需要了解两个类:Proxy: 代理类,InvocationHandler : 调用处理程序

      从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

      //Proxy是生成动态代理类,提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
      //InvocationHandler-- invoke 调用处理程序并返回接口, 是由代理实例的调用处理程序实现的接口 。

      动态代理的好处:

      • 可以使真实角色的操作更加纯粹!不用去关系一些公共的业务

      • 公共也就交给代理角色!实现

      public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h){
      }

      1.loader :类加载器,用于加载代理对象。

      2.interfaces : 被代理类实现的一些接口;

      3.h : 实现了 InvocationHandler 接口的对象;

      要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。

      public interface InvocationHandler {
          Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
      }

      1.proxy :动态生成的代理类

      2.method : 与代理类对象调用的方法相对应

      3.args : 当前 method 方法的参数

      动态代理的例子

      1、定义接口

      public interface Rent {
          public void rent();
      }

      2、实现租房的接口

      public class Host implements Rent {
          @Override
          public void rent() {
              System.out.println("房东要租房");
          }
      }

      3、定义一个JDK动态代理类

      public class DebugInvocationHandler implements InvocationHandler {
          /**
           * 代理类中的真实对象
           */
          private final Object target;
          public DebugInvocationHandler(Object target){
              this.target = target;
          }
          /**
           * 当你使用代理对象调用方法的时候实际会调用到这个方法
           */
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              //调用方法前
              System.out.println("before method" + method.getName());
              Object res = method.invoke(target, args);
              //调用方法后
              System.out.println("after method" + method.getName());
              return res;
          }
      }

      invoke() 方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法,然后 invoke() 方法代替我们去调用了被代理对象的原生方法。

      4、获取代理对象的工厂类

      public class JdkProxyFactory {
          public static Object getProxy(Object target){
              return Proxy.newProxyInstance(
                      target.getClass().getClassLoader(),
                      target.getClass().getInterfaces(),
                      new DebugInvocationHandler(target)
              );
          }
      }

      getProxy() :主要通过Proxy.newProxyInstance()方法获取某个类的代理对象

      5、实际使用

      public static void main(String[] args) {
              //Rent rent = new Host();
              //Rent rentProxy= (Rent) Proxy.newProxyInstance(rent.getClass().getClassLoader(), rent.getClass().getInterfaces(),new DebugInvocationHandler(rent));
              Rent rentProxy = (Rent)JdkProxyFactory.getProxy(new Host());
              rentProxy.rent();
          }

      运行上述代理的输出

      before methodrent
      房东要租房
      after methodrent

      本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
      作者最新文章
      编程开发 Java
      相关文章 更多
      Java单元测试入门:使用JUnit 5编写第一个测试用例
      Java单元测试入门:使用JUnit 5编写第一个测试用例

      面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

      Java变量未初始化报错解析:局部变量与成员变量默认值差异
      Java变量未初始化报错解析:局部变量与成员变量默认值差异

      深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

      Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
      Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

      详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

      Java中final与static final常量的定义及初始化规则
      Java中final与static final常量的定义及初始化规则

      深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

      Java抽象方法与接口方法的区别及选型建议
      Java抽象方法与接口方法的区别及选型建议

      深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

      Java实现HTTP请求与JSON解析的完整代码示例
      Java实现HTTP请求与JSON解析的完整代码示例

      本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

      Java递归出现StackOverflowError的原因分析及栈空间优化方案
      Java递归出现StackOverflowError的原因分析及栈空间优化方案

      详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

      Java空指针异常(NPE)的代码排查与修复实例
      Java空指针异常(NPE)的代码排查与修复实例

      针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

      selenium上传文件教程本地文件路径设置方法
      selenium上传文件教程本地文件路径设置方法

      深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

      大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
      大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

      针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

      查看更多
      精品专题 更多
      装机必备
      装机必备

      正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

      Windows
      Windows

      正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

      PDF教程
      PDF教程

      正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

      Mac软件 更多
      讯飞智作 网页版
      讯飞智作 网页版
      Windows/ macOS/ Linux

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      火山引擎 网页版
      火山引擎 网页版
      Windows/ macOS/ Linux

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      Aperty macOS版
      Aperty macOS版
      macOS

      Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

      WINDOWS 更多
      讯飞智作 网页版
      讯飞智作 网页版
      Windows/ macOS/ Linux

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      火山引擎 网页版
      火山引擎 网页版
      Windows/ macOS/ Linux

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      PixTV 网页版
      PixTV 网页版
      Windows

      PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。