jdk动态代理(Proxy,InvocationHandler),含$Proxy0源码

2024-02-05 19:38

本文主要是介绍jdk动态代理(Proxy,InvocationHandler),含$Proxy0源码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载:http://ldbjakyo.iteye.com/blog/724725

 

 

一.相关类及其方法:

java.lang.reflect.Proxy,
Proxy 提供用于创建动态代理类和实例的静态方法.
newProxyInstance()
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
(详见api文档)

java.lang.reflect.InvocationHandler,
InvocationHandler 是代理实例的调用处理程序 实现的接口。
invoke()
在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
(详见api文档)

二.源代码:

被代理对象的接口及实现类:

package com.ml.test;public interface Manager {
public void modify();
}package com.ml.test;public class ManagerImpl implements Manager {@Override
public void modify() {System.out.println("*******modify()方法被调用");
}
}


业务代理类:

package com.ml.test;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class BusinessHandler implements InvocationHandler {private Object object = null;public BusinessHandler(Object object) {this.object = object;
}@Override
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("do something before method");Object ret = method.invoke(this.object, args);System.out.println("do something after method");return ret;}
}




客户端类:

package com.ml.test;
import java.lang.reflect.Proxy;
public class Client {public static void main(String[] args) {// 元对象(被代理对象)ManagerImpl managerImpl = new ManagerImpl();// 业务代理类BusinessHandler securityHandler = new BusinessHandler(managerImpl);// 获得代理类($Proxy0 extends Proxy implements Manager)的实例.Manager managerProxy = (Manager) Proxy.newProxyInstance(managerImpl.getClass().getClassLoader(), managerImpl.getClass().getInterfaces(), securityHandler);managerProxy.modify();
}
}


三.执行结果:
do something before method
*******modify()方法被调用
do something after method

四.机制分析:

Proxy.(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)做了以下几件事.
(1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy.
$Proxy0类实现了interfaces的接口,并继承了Proxy类.
(2)实例化$Proxy0并在构造方法中把BusinessHandler传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值,如下:

class Proxy{InvocationHandler h=null;protected Proxy(InvocationHandler h) {this.h = h;}...
}





下面是本例的$Proxy0类的源码(好不容易才把它提出来,改了JRE源码,打印出字节码,把字节码保存为class文件,并反编译class文件):

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements Manager {private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;static {try {m1 = Class.forName("java.lang.Object").getMethod("equals",new Class[] { Class.forName("java.lang.Object") });m0 = Class.forName("java.lang.Object").getMethod("hashCode",new Class[0]);m3 = Class.forName("com.ml.test.Manager").getMethod("modify",new Class[0]);m2 = Class.forName("java.lang.Object").getMethod("toString",new Class[0]);} catch (NoSuchMethodException nosuchmethodexception) {throw new NoSuchMethodError(nosuchmethodexception.getMessage());} catch (ClassNotFoundException classnotfoundexception) {throw new NoClassDefFoundError(classnotfoundexception.getMessage());}
}public $Proxy0(InvocationHandler invocationhandler) {super(invocationhandler);
}@Override
public final boolean equals(Object obj) {try {return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })).booleanValue();} catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}
}@Override
public final int hashCode() {try {return ((Integer) super.h.invoke(this, m0, null)).intValue();} catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}
}public final void modify() {try {super.h.invoke(this, m3, null);return;} catch (Error e) {} catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}
}@Override
public final String toString() {try {return (String) super.h.invoke(this, m2, null);} catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}
}
}


接着把得到的$Proxy0实例强制转换成Manager.
当执行managerProxy.modify()方法时,就调用了$Proxy0类中的modify()方法.
在modify方法中,调用父类Proxy中的h的invoke()方法.
即InvocationHandler.invoke();

 

 

这篇关于jdk动态代理(Proxy,InvocationHandler),含$Proxy0源码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/681943

相关文章

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja

Linux系统中查询JDK安装目录的几种常用方法

《Linux系统中查询JDK安装目录的几种常用方法》:本文主要介绍Linux系统中查询JDK安装目录的几种常用方法,方法分别是通过update-alternatives、Java命令、环境变量及目... 目录方法 1:通过update-alternatives查询(推荐)方法 2:检查所有已安装的 JDK方

在macOS上安装jenv管理JDK版本的详细步骤

《在macOS上安装jenv管理JDK版本的详细步骤》jEnv是一个命令行工具,正如它的官网所宣称的那样,它是来让你忘记怎么配置JAVA_HOME环境变量的神队友,:本文主要介绍在macOS上安装... 目录前言安装 jenv添加 JDK 版本到 jenv切换 JDK 版本总结前言China编程在开发 Java

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

JAVA中安装多个JDK的方法

《JAVA中安装多个JDK的方法》文章介绍了在Windows系统上安装多个JDK版本的方法,包括下载、安装路径修改、环境变量配置(JAVA_HOME和Path),并说明如何通过调整JAVA_HOME在... 首先去oracle官网下载好两个版本不同的jdk(需要登录Oracle账号,没有可以免费注册)下载完

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

springboot如何通过http动态操作xxl-job任务

《springboot如何通过http动态操作xxl-job任务》:本文主要介绍springboot如何通过http动态操作xxl-job任务的问题,具有很好的参考价值,希望对大家有所帮助,如有错... 目录springboot通过http动态操作xxl-job任务一、maven依赖二、配置文件三、xxl-

Mac系统下卸载JAVA和JDK的步骤

《Mac系统下卸载JAVA和JDK的步骤》JDK是Java语言的软件开发工具包,它提供了开发和运行Java应用程序所需的工具、库和资源,:本文主要介绍Mac系统下卸载JAVA和JDK的相关资料,需... 目录1. 卸载系统自带的 Java 版本检查当前 Java 版本通过命令卸载系统 Java2. 卸载自定

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔