Dubbo源码解析-动态编译javaAssist的使用
2021/11/22 12:39:52
本文主要是介绍Dubbo源码解析-动态编译javaAssist的使用,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言:
在Dubbo中,大量使用动态代理相关技术。动态代理主要是基于JDK的动态代理和Javassist的动态代理。
有关于JDK动态代理的使用及源码解析可以参考上文。
本文着重来介绍下Javassist的使用,及其动态代理的实现。
1.Javassist简介
Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。(来自百度百科)
通过这个介绍,我们了解到javassist可以操作java字节码,而通过操作字节码,还能实现动态代理。
2.Javassist的基本使用
2.1 引入maven依赖
<dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.25.0-GA</version> </dependency>
2.2 创建实体类
package xw.demo.proxy.javassist; public class Student { private String name; private int age; // 省略get set方法 public String study(String book) { return name + "study " + book; } }
2.3 基本API使用
2.3.1 ClassPool加载已知类
ClassPool pool = ClassPool.getDefault(); // 加载Student CtClass studentClass = pool.get("xw.demo.proxy.javassist.Student");
2.3.2 CtField获取属性
CtField nameField = studentClass.getField("name"); // 获取属性类型,本例中即为java.lang.String String nameType = nameField.getType().getName(); // 获取属性注解 Object[] annotations = nameField.getAnnotations(); ...
2.3.3 CTMethod获取方法信息
CtMethod method = studentClass.getDeclaredMethod("study"); // 获取方法返回类型 CtClass returnType = method.getReturnType(); // 获取方法参数类型 CtClass[] parameterTypes = method.getParameterTypes();
2.3.4 CtConstructor获取构造方法信息
CtConstructor[] declaredConstructors = studentClass.getDeclaredConstructors(); if (null != declaredConstructors) { for (CtConstructor ctConstuctor : declaredConstructors) { // 获取构造方法名称 String name = ctConstuctor.getName(); // 获取构造方法参数类型 CtClass[] ctConstuctorParameterTypes = ctConstuctor.getParameterTypes(); } }
javassist的使用还是比较简单的。但这只是开胃菜,真正重要的是其用来动态创建一个新的类。下面我们就用Javassist来创建一个新的Student类,与上述有一样的属性和方法。
2.3.5 javassist创建新的类
public static void newClassTest() { ClassPool pool = ClassPool.getDefault(); // 创建class信息 CtClass studentClass = pool.makeClass("xw.demo.proxy.javassist.Student_copy"); try { // 创建name属性 CtField nameField = new CtField(pool.get("java.lang.String"), "name", studentClass); nameField.setModifiers(Modifier.PUBLIC); studentClass.addField(nameField); // 创建age属性 CtField ageField = new CtField(CtClass.intType, "age", studentClass); ageField.setModifiers(Modifier.PUBLIC); studentClass.addField(ageField); CtMethod studyMethod = new CtMethod(pool.get("java.lang.String"), "study", new CtClass[]{pool.get("java.lang.String")}, studentClass); studyMethod.setModifiers(Modifier.PUBLIC); studyMethod.setBody("return name + \"study \" + $1;"); studentClass.addMethod(studyMethod); // 写出到文件 studentClass.writeFile("D:\\test"); } catch (CannotCompileException | IOException e) { e.printStackTrace(); } catch (NotFoundException e) { e.printStackTrace(); } }
最终会生成一个Student_copy.class,具体信息如下
package xw.demo.proxy.javassist; public class Student_copy { public String name; public int age; public String study(String paramString) { return this.name + "study " + paramString; } }
2.4 动态代理的创建
之前有写过通过JDK proxy来实现动态代理的文章,使用JDK自带的还是比较方便的。那么当我们使用Javassist该如何实现动态代理呢,实际也是很简单的。直接看示例。
2.4.1 创建示例方法
// 创建被代理类 public class EchoService { public String echo(String msg) { return "echo " + msg; } } public static void proyTest() { ClassPool pool = new ClassPool(); try { CtClass echoServiceClass = pool.get("xw.demo.proxy.javassist.EchoService"); // 获取其echo方法,并在方法前后添加执行语句 CtMethod echoMethod = echoServiceClass.getDeclaredMethod("echo"); echoMethod.insertBefore("before echo..."); echoMethod.insertAfter("after echo..."); // 执行echo方法 EchoService echoService = (EchoService)echoServiceClass.toClass().newInstance(); String world = echoService.echo("world"); System.out.println(world); } catch (NotFoundException | CannotCompileException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } // 执行结果: before echo... echo world after echo...
Javassist通过对字节码的执行,在方法执行的前后添加自定义代码,就可以实现对方法的动态代理。
2.4.2 Dubbo中Javassist动态代理的使用
Dubbo使用Javassist来实现动态代理,代码如下:
public class JavassistProxyFactory extends AbstractProxyFactory { @Override @SuppressWarnings("unchecked") public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) { // 具体可见getProxy()方法 return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); } }
具体细节笔者就不再展示,也是通过动态生成一个Proxy类,来实现对invoker的动态代理的。
这篇关于Dubbo源码解析-动态编译javaAssist的使用的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-11cursor试用出现:Too many free trial accounts used on this machine 的解决方法
- 2025-01-11百万架构师第十四课:源码分析:Spring 源码分析:深入分析IOC那些鲜为人知的细节|JavaGuide
- 2025-01-11不得不了解的高效AI办公工具API
- 2025-01-102025 蛇年,J 人直播带货内容审核团队必备的办公软件有哪 6 款?
- 2025-01-10高效运营背后的支柱:文档管理优化指南
- 2025-01-10年末压力山大?试试优化你的文档管理
- 2025-01-10跨部门协作中的进度追踪重要性解析
- 2025-01-10总结 JavaScript 中的变体函数调用方式
- 2025-01-10HR团队如何通过数据驱动提升管理效率?6个策略
- 2025-01-10WBS实战指南:如何一步步构建高效项目管理框架?