Jdk动态代理源码

server/2024/9/25 15:29:12/

Proxy

代码: java.lang.reflect.Proxy

Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。

构造一个新的Proxy实例,并指定调用处理器 InvocationHandler。

    protected Proxy(InvocationHandler h) {Objects.requireNonNull(h);this.h = h;}

InvocationHandler

InvocationHandler 经常和 Proxy 配合使用。

InvocationHandler是由代理实例的调用处理程序实现的接口。

每个代理实例都有一个关联的调用处理程序。当在代理实例上调用方法时,方法调用会被编码并分派给其调用处理程序的 invoke 方法。

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

Proxy 和 InvocationHandler 代码示例

可以通过一个简单的示例, 了解下 Proxy 和 InvocationHandler 的使用。

  • MyInterface :
public interface MyInterface {String doSomething();
}
  • MyInterfaceImpl :
public class MyInterfaceImpl implements MyInterface {@Overridepublic String doSomething() {System.out.println("MyInterfaceImpl doSomething");return "doSomething result";}}
  • MyInvocationHandler:
public class MyInvocationHandler implements InvocationHandler {/*** 目标对象*/private final Object target;/*** 调用处理器的构造方法,以目标对象作为参数* @param target*/public MyInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//以下是一个简单的 AOP//前置处理System.out.println("before doSomething.");//反射,调用目标对象的方法Object result = method.invoke(target, args);//后置处理System.out.println("after doSomething.");return result;}}
  • ProxyDemo 示例:
public class ProxyDemo {public static void main(String[] args) throws Exception {//保存代理产生的类文件,方便查看 com.sun.proxy.$Proxy0 的源码System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");//被代理的目标对象MyInterface myInterfaceImpl = new MyInterfaceImpl();//自定义调用处理器 InvocationHandler , 以目标对象为参数InvocationHandler invocationHandler = new MyInvocationHandler(myInterfaceImpl);//Jdk动态代理支持的 Class对象必须是一个接口,否则会报错 IllegalArgumentException:is not an interfaceMyInterface myInterface = (MyInterface) Proxy.newProxyInstance(MyInterface.class.getClassLoader(),new Class<?>[] { MyInterface.class },invocationHandler);//调用的实际是动态代理生成的 com.sun.proxy.$Proxy0 对象的 doSomething()方法myInterface.doSomething();}}

源码 com.sun.proxy.$Proxy0

com.sun.proxy.Proxy0 继承了Proxy类,并实现了示例代码中的 MyInterface。
示例中加入以下代码,会保存代理产生的类文件,方便查看 com.sun.proxy.Proxy0 的源码。

        //保存代理产生的类文件,方便查看 com.sun.proxy.$Proxy0 的源码System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

为什么调用代理对象的方法,就会调用自定义的 MyInvocationHandler 中的 invoke()方法?
可以看一下 com.sun.proxy.$Proxy0的源码。运行示例代码后,会自动生成这个类。

实际上调用的是父类Proxy的 InvocationHandler h 的 invoke()方法。
也就是示例代码中的 MyInvocationHandler类的 invoke() 方法。

public final class $Proxy0 extends Proxy implements MyInterface {private static Method m1;private static Method m3;private static Method m2;private static Method m0;public $Proxy0(InvocationHandler var1) throws  {super(var1);}public final boolean equals(Object var1) throws  {try {return (Boolean)super.h.invoke(this, m1, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}/***   核心代码。重点看看。*/public final String doSomething() throws  {try {//为什么调用代理对象的方法,就会调用自定义的 MyInvocationHandler 中的 invoke()方法//实际上调用的是父类Proxy的 InvocationHandler h 的 invoke()方法。//也就是示例代码中的 MyInvocationHandler类的 invoke() 方法。return (String)super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final String toString() throws  {try {return (String)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final int hashCode() throws  {try {return (Integer)super.h.invoke(this, m0, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));// 这个m3,就是要被代理的目标接口 MyInterface 的 doSomething方法m3 = Class.forName("com.example.demo.sourceCode.proxy.MyInterface").getMethod("doSomething");m2 = Class.forName("java.lang.Object").getMethod("toString");m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}

源码 Proxy.newProxyInstance

源码: java.lang.reflect.Proxy#newProxyInstance

newProxyInstance() 是代理类经常用的方法。

newProxyInstance() 方法返回指定接口的代理类实例,该代理类将方法调用分派给指定的调用处理程序(InvocationHandler)。

    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{Objects.requireNonNull(h);final Class<?>[] intfs = interfaces.clone();final SecurityManager sm = System.getSecurityManager();if (sm != null) {checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}/** 查找或生成指定的代理类。*/Class<?> cl = getProxyClass0(loader, intfs);try {if (sm != null) {checkNewProxyPermission(Reflection.getCallerClass(), cl);}final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);return null;}});}//使用指定的调用处理程序(InvocationHandler)调用其构造函数。//Constructor构造方法的 newInstance() 是支持 InvocationHandler转换为 Object 作为参数的。return cons.newInstance(new Object[]{h});} catch (IllegalAccessException|InstantiationException e) {throw new InternalError(e.toString(), e);} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString(), t);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString(), e);}}

Jdk 动态代理的缺点

Jdk 动态代理 只支持接口级别的动态代理, 如果提供的不是接口,就会报错:

java.lang.IllegalArgumentException:  is not an interface

源码:java.lang.reflect.Proxy.ProxyClassFactory#apply

  //验证Class对象是否实际表示接口。如果不是接口,就会报错。if (!interfaceClass.isInterface()) {throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");}

http://www.ppmy.cn/server/121878.html

相关文章

分布式事务(2)

2.2.部署TC服务 2.2.1.准备数据库表 Seata支持多种存储模式&#xff0c;但考虑到持久化的需要&#xff0c;我们一般选择基于数据库存储。执行课前资料提供的《seata-tc.sql》&#xff0c;导入数据库表&#xff1a; 2.2.2.准备配置文件 一个seata目录&#xff0c;其中包含了…

SpringBoot项目创建

1. Spring 介绍 Spring的官网&#xff1a; https://spring.io Spring的官方提供很多开源的项目&#xff0c;我们可以点击上面的projects&#xff0c;看到spring家族旗下的项目&#xff0c; 按照流行程度排序为&#xff1a; Spring发展到今天已经形成了一种开发生态圈&#x…

光伏设计:五秒铺设光伏板

光伏板作为太阳能利用的核心组件&#xff0c;其设计、安装与运维的效率直接影响到太阳能发电系统的整体性能与成本。 一、智能选型&#xff1a;光伏板种类型号的精准匹配 通过智能系统对安装地点的气候条件、光照资源、电网接入条件等因素进行综合分析&#xff0c;快速筛选出最…

递归快速获取机构树型图

一般组织架构都会有层级关系&#xff0c;根部门的parentId一般设置为null或者0等特殊字符&#xff0c;而次级部门及以下的parentId则指向他们父节点的id。 以此为基础&#xff0c;业务上经常会有查询整个组织架构层级关系的需求&#xff0c;返回对象中的children属性用来存储子…

Mac 命令行常用操作笔记

1. 启用和禁用 Wi-Fi 打开 Wi-Fi&#xff1a; sudo networksetup -setairportpower "Wi-Fi" on 关闭 Wi-Fi&#xff1a; sudo networksetup -setairportpower "Wi-Fi" off 2. 搜索并连接 Wi-Fi 切换到 airport 工具目录&#xff1a; cd /System/Librar…

JavaScript动态数据可视化

一、引言 在前端开发中&#xff0c;JavaScript无疑是最核心的技术之一。它能够处理各种交互逻辑&#xff0c;实现复杂的功能。本文将通过一个动态数据可视化的案例&#xff0c;展示如何使用JavaScript实现复杂功能。动态数据可视化能够将大量数据以直观、生动的方式呈现&#…

AUTOSAR_EXP_ARAComAPI的5章笔记(9)

☞ 返回总目录 5.4 骨架类&#xff08;Skeleton Class&#xff09; 骨架类是由AUTOSAR 元模型的服务接口描述&#xff08;SI description&#xff09;生成的。ara::com对生成的骨架类的接口进行了标准化。自适应平台&#xff08;AP&#xff09;产品供应商的工具链将生成一个完…

网安面试会问到的:http的长连接和短连接

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 《Java代码审…