手写一个JDK动态代理的简单实现
前言
在【设计模式】——代理模式(静态)以及【设计模式】——代理模式(动态)中,我们已经基本了解了什么是代理模式,以及什么是静态代理,什么是动态代理。JDK动态代理以及Cglib动态代理其实底层实现原理都是字节码的重组,不过各自对应的代理场景不同,本文我们重点研究jdk动态代理。
通过前文的了解,我们已经知道在JDK动态代理中是JDK动态的帮我们生成一个名为$Proxy0的代理类,那么,我们本文来纯手写实现JDK动态代理,也就是我们自己生成这个代理类,与JDK动态代理的思想一致,只为简化,细节部分本文并未过多研究。
实现
在前文动态代理实现jdk动态代理中我们有这样一个类的调用关系图
其中需要引用到jdk的Proxy和InvocationHandler这两个类,这里我们自己简单实现MyProxy.java和MyInvocationHandler.java,由于需要动态生成代理类,那么就需要生成,编译,加载到jvm,因此我们实现了一个简单的类加载器MyClassLoader.java,此时类调用关系图略微变化
不多说,上代码,大多地方都有比较详细的注释
MyInvocationHandler.java
/** 用于自定义代理逻辑处理
* @author WangZhiJun
*/
public interface MyInvocationHandler {
/** invoke
* @param proxy 指被代理的对象
* @param method 要调用的方法
* @param args 方法调用时所需要的参数
* @return Object
* @throws Throwable 异常
*/
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
MyProxy.java
这个类就是JDK动态代理的关键,其中进行了代理类的动态生成:
- 生成源代码
- 将生成的源代码输出到磁盘,保存为.java文件
- 编译源代码,并且生成.class文件
- 将class文件中的内容,动态加载到JVM中来
- 返回被代理后的代理对象
/** 生成代理对象的代码
* @author WangZhiJun
*/
class MyProxy {
private static final String ln = "\r\n";
/** 通过此类为一个或多个接口动态的生成实现类
* @param classLoader 类加载器
* @param interfaces 得到全部的接口
* @param h 得到InvocationHandler接口的子类实例
* @return Object
*/
static Object newProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler h){
try{
//1、生成源代码
String proxySrc = generateSrc(interfaces[0]);
//2、将生成的源代码输出到磁盘,保存为.java文件
String filePath = MyProxy.class.getResource("").getPath();
File f = new File(filePath + "$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(proxySrc);
fw.flush();
fw.close();
//3、编译源代码,并且生成.class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
Iterable iterable = manager.getJavaFileObjects(f);
CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
task.call();
manager.close();
//4.将class文件中的内容,动态加载到JVM中来
//5.返回被代理后的代理对象
Class proxyClass = classLoader.findClass("$Proxy0");
Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
//这里先不删除生成的$Proxy0.java文件,实际上要删除的
f.delete();
return c.newInstance(h);
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
/** 生成代理对象$Proxy0的源代码
* @param interfaces 抽象对象
* @return String
*/
private static String generateSrc(Class<?> interfaces){
StringBuilder src = new StringBuilder();
src.append("package com.wang.proxy.custom.jdk.proxy;" + ln);
//引入反射相关的包
src.append("import java.lang.reflect.Method;" + ln);
//动态代理类实现被代理接口,在此为Person类
src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
src.append("MyInvocationHandler h;" + ln);
src.append("public $Proxy0(MyInvocationHandler h) {" + ln);
src.append("this.h = h;" + ln);
src.append("}" + ln);
//通过反射获取代理接口的所有方法并激活
for (Method m : interfaces.getMethods()) {
src.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln);
src.append("try{" + ln);
src.append("Method m = " + interfaces.getName() + ".class.getMethod(\"" +m.getName()+"\",new Class[]{});" + ln);
src.append("this.h.invoke(this,m,null);" + ln);
src.append("}catch(Throwable e){e.printStackTrace();}" + ln);
src.append("}" + ln);
}
src.append("}");
return src.toString();
}
}
MyClassLoader.java
/**将class重新动态load到JVM
* @author WangZhiJun
*/
public class MyClassLoader extends ClassLoader{
private File baseDir;
MyClassLoader(){
String basePath = MyClassLoader.class.getResource("").getPath();
this.baseDir = new File(basePath);
}
@Override
protected Class<?> findClass(String name) {
String className = MyClassLoader.class.getPackage().getName() + "." + name;
if(baseDir != null){
File classFile = new File(baseDir,name.replaceAll("\\.", "/") + ".class");
if(classFile.exists()){
FileInputStream in = null;
ByteArrayOutputStream out = null;
try{
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte [] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
return defineClass(className, out.toByteArray(), 0,out.size());
}catch (Exception e) {
e.printStackTrace();
}finally{
if(null != in){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null != out){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//先不删除,可以看到class文件内容
//classFile.delete();
}
}
}
return null;
}
}
开始测试
SomeService.java
//主业务接口
public interface SomeService {
String first();
String second();
}
SomeServiceImpl.java
//目标类
public class SomeServiceImpl implements SomeService{
public String first() {
// TODO Auto-generated method stub
return "I Love You";
}
public String second() {
// TODO Auto-generated method stub
return "China";
}
}
SomeServiceProxy.java
public class SomeServiceProxy implements MyInvocationHandler {
private SomeService someService;
public void setSomeService(SomeService someService) {
this.someService = someService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(args);
}
public SomeService creatProxy() {
SomeService proxy = (SomeService) MyProxy.newProxyInstance(new MyClassLoader(), someService.getClass().getInterfaces(), this);
return proxy;
}
}
Main方法
public static void main(String[] args) {
//创建目标类
SomeService someService = new SomeServiceImpl();
//创建代理类
SomeServiceProxy someServiceProxy = new SomeServiceProxy();
//传入目标类
someServiceProxy.setSomeService(someService);
//创建代理类
SomeService proxy = someServiceProxy.creatProxy();
//执行代理类方法
proxy.first();
}
或者在SomeService和SomeServiceImpl的基础上直接这样写实现动态代理
public static void main(String[] args) {
//创建目标类
SomeService someService = new SomeServiceImpl();
SomeService proxy = (SomeService) MyProxy.newProxyInstance(new MyClassLoader(), someService.getClass().getInterfaces(), new MyInvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
proxy.first();
}
我们看看这个动态生成的$Proxy0代理类是怎么写的
public class $Proxy0 implements SomeService{
MyInvocationHandler h;
public $Proxy0(MyInvocationHandler var1) {
this.h = var1;
}
public void findLove() {
try {
Method var1 = SomeService.class.getMethod("first");
this.h.invoke(this, var1, (Object[])null);
} catch (Throwable var2) {
var2.printStackTrace();
}
}
}
这就是生成的动态代理类
此时我们就简单的实现了JDK的动态代理,不过JDK中实际的实现会更加复杂,更加细节!
文章转自:https://blog.csdn.net/qq_37141773/article/details/100015741
-------------------------------------------
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!