首页 > 编程语言 >Java中的代理模式(动态代理和静态代理)

Java中的代理模式(动态代理和静态代理)

时间:2024-03-22 10:32:05浏览次数:25  
标签:调用 Java newProxyInstance 静态 代理 InvocationHandler 动态 方法

代理模式

我们先了解一下代理模式:

在开发中,当我们要访问目标类时,不是直接访问目标类,而是访问器代理类。通过代理类调用目标类完成操作。简单来说就是:把直接访问变为间接访问。

这样做的最大好处就是:我们可以在代理类调用目标类之前和之后去添加一些预处理和后处理操作。来扩展一些不属于目标类的功能。

比如说:我们可以在方法开始和结束前记录日志:在方法执行前进行额外的参数校验,进行事务管理,如手动提交、权限校验等。

代理模式是一种设计思想,实际实现方式上有静态代理动态代理之分。

1.静态代理

静态代理:在程序运行前,我们就给目标类编写了其代理类的代码,然后编译了其代理类。这样在程序运行之前,我们就已经生成了它代理类的字节码文件,即我们事先编写,然后编译,在程序运行的时候直接去读这些字节码文件进行运行。

例:定义静态代理类

使用静态代理类:

这里使用student调用dowork和使用staticProxy调用dowork效果不一样,后者在原有功能基础上增加了调用方法前和调用方法后的打印功能。

这就我们代理模式的最大特点:它可以控制对原有对象的访问。在原有对象的访问的基础上去做一些额外的能力。

这些类已经被编译为字节码文件了,我们可以拿这几个文件去任何一个机器上执行。

如果是静态代理的话,我们需要编写一个与其绑定的代理类。这个类会被编译成字节码文件,然后再运行。

2.动态代理

而如果是动态代理的话,我们就不需要是献给目标去编写代理代码,而是在运行中通过反射自动生成代理对象!

在Java中,动态代理主要通过两种机制实现:JDK动态代理和CGLIB动态代理。

2.1JDK动态代理

JDK动态代理基于Java的反射机制,它只能为接口创建代理对象。要使用JDK动态代理,需要实现java.lang.reflect.InvocationHandler接口,并重写其invoke()方法。invoke()方法会在代理对象上的方法被调用时被执行。

例:

这里最核心的就是通过Proxy.newProxyInstance方法去生成动态代理类以及访问它的实例。

使用动态代理:

这里dynamicProxyList就是动态代理对象,它会自动调用动态代理类DynamicProxy重写的invoke方法,打印两次开始执行是因为调用了dynamicProxyList的toString方法。

在这里我们并没有编写ArrayList的代理类,但是却把它代理了,这就是动态代理的魅力。

问题来了:这个它的动态代理类生成在哪里呢?我们怎么没看见呢?

原理:

@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {
        Objects.requireNonNull(h);
        Class<?> caller = System.getSecurityManager() == null ? null : Reflection.getCallerClass();
        Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
        return newProxyInstance(caller, cons, h);
    }
2.1.1caller

        caller是一个内部类,用于代表创建代理实例的调用者。这个caller类实际上是一个

InvocationHandler的实现,它负责在代理实例上转发方法调用。

newProxyInstance方法的实现中,caller类并不是直接作为参数传递给newProxyInstance方法的,而是在内部被创建和使用。这个类通常是一个匿名内部类,它的主要作用是持有对原始InvocationHandler的引用,并将方法调用转发给该处理器。

2.1.2cons

        在 Java 中,`Proxy.newProxyInstance()` 方法的源码中的 `cons` 表示 `constructor`,它用来表示代理类的构造函数。在 `Proxy.newProxyInstance()` 方法内部,会调用代理类的构造函数来创建实际的代理对象。

具体来说,`Proxy.newProxyInstance()` 方法的源码中会根据传入的类加载器(`ClassLoader`)、接口数组(`Class[]`)和 `InvocationHandler` 对象来动态生成代理类,并通过代理类的构造函数来创建代理对象。生成的代理类会实现传入的接口,并将接口中的方法调用委托给传入的 `InvocationHandler` 对象来处理。

代理类的构造函数在代理对象实例化时会被调用,并在内部完成代理对象的初始化工作,比如将 `InvocationHandler` 对象赋值给代理对象。

因此,在 `Proxy.newProxyInstance()` 方法源码中的 `cons` 所指的就是代理类的构造函数,用来创建代理对象并完成代理对象的初始化工作。

实现思路:代理类(运行时生成的代理类)和被代理类(这里就是ArrayList)实现同一个接口,有被代理类的所有方法,然后代理类把被代理类所有方法原先的调用通通先去调用代理类的InvocationHandler(也就是我们自己写的那个代理类)

在这个例子中共有32个Method(方法)对象,对应的就是List的32个方法。

如这里某个方法进行代理,我们可以看到这里它调用的是h的invoke方法,这个h就是我们之前写的InvocationHandler的实现类(DynamicProxy(我们自己写的实现Invocation的动态代理类)和这个$Proxy0代理类是两个东西!!!)  这样目标类的所有方法都会走我们写的那个通用代理类(DynamicProxy)的invoke方法。

标签:调用,Java,newProxyInstance,静态,代理,InvocationHandler,动态,方法
From: https://blog.csdn.net/qq_64064246/article/details/136909889

相关文章

  • JAVA对象、类和基本数据类型
    变量和标识符数学名词:变数或变量,是指没有固定的值,可以改变的数。变量以非数字的符号来表示,一般用拉丁字母。变量和常数是相反的。变量的用处在于能一般化描述指令的方式计算机解释:变量就是系统为程序分配的一块内存单元,用来储存各种类型的数据。根据所储存的数据类型不同,有......
  • Java面试相关问题
     一.MySql篇1优化相关问题1.1.MySql中如何定位慢查询? 慢查询的概念:在MySQL中,慢查询是指执行时间超过一定阈值的SQL语句。这个阈值是由long_query_time参数设定的,它的默认值是10秒1。也就是说,如果一条SQL语句的执行时间超过了long_query_time所设定的时间,那么这条SQL......
  • JAVA基本数据类型转换、关键字、转义字符
    基本数据类型转换自动类型转换:容量小的类型自动转换成容量大的数据类型byte,short,它们在计算时会转换int类型如果把int转换成float值,或者long转换成double值,不需要强制转换,但可能丢失精度publicclassMain{publicstaticvoidmain(String[]args){byteb......
  • 深入解析Mybatis-Plus框架:简化Java持久层开发(十二)
    ......
  • Java使用数据库连接池
    一、原生JDBC操作数据库的步骤(1)加载数据库驱动。(2)获取数据库连接。(3)预编译SQL语句。(4)执行SQL。(5)获取结果集。(6)释放资源。示例代码如下:publicclassJDBCTest{    publicstaticvoidmain(String[]args)throwsClassNotFoundException,SQLException......
  • Day01 文学生也想学java之今天我也许学能学会Markdown
    Day01文学生也想学java之今天我也许学能学会Markdown1.标题一级标题:#+(空格)+标题内容二级标题:##+(空格)+标题内容......(以此类推)2.字体helloworld!:前后两个*helloworld!:前后一个*helloworld!:前后三个*helloworld!:前后两个~3.引用这是一句引用:引用=>+(空格)4.分割线---+......
  • 毕业设计课题:实验室课程管理系统,基于java+SSM+mysql
          一、前言介绍     如今互联网发展迅猛,大量的信息都是通过网络这一渠道来传播,所以利用网络渠道来传播知识是非常有前景的。线上管理系统的主要目的是对实验室课程信息进行更有效的管理,光靠现有的管理方式是远远不够的,因此开发实验室课程管理系统是有必要的......
  • 毕业设计课题:少儿编程管理系统,基于java+SSM+mysql
          一、前言介绍     21世纪,我国早在上世纪就已普及互联网信息,互联网对人们生活中带来了无限的便利。像大部分的企事业单位都有自己的系统,由从今传统的管理模式向互联网发展,如今开发自己的系统是理所当然的。那么开发少儿编程管理系统意义和用处有哪些呢? ......
  • 获取代理IP
    #流冠IP获取代理#提取订单"""orderId:提取订单号secret:用户密钥num:提取IP个数pid:省份cid:城市type:请求类型,1=http/https,2=socks5unbindTime:使用时长,秒/s为单位noDuplicate:去重,0=不去重,1=去重lineSeparator:分隔符si......
  • Jackson进行JSON序列化/反序列化添加Java 8的日期和时间库支持
     添加依赖包<!--Jackson进行JSON序列化/反序列化添加Java8的日期和时间库支持--> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.13.0</version> ......