Javassist字节码增强示例
概述
- private static ClassLoader getLocaleClassLoader() throws Exception {
- List<URL> classPathURLs = new ArrayList<>();
- // 加载.class文件路径
- classPathURLs.add(classesPath.toURI().toURL());
- // 获取所有的jar文件
- File[] jarFiles = libPath.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.endsWith(".jar");
- }
- });
- Assert.assertFalse(ObjectHelper.isArrayNullOrEmpty(jarFiles));
- // 将jar文件路径写入集合
- for (File jarFile : jarFiles) {
- classPathURLs.add(jarFile.toURI().toURL());
- }
- // 实例化类加载器
- return new URLClassLoader(classPathURLs.toArray(new URL[classPathURLs.size()]));
- }
获取类型信息
- @Test
- public void test() throws NotFoundException {
- // 获取默认类型池对象
- ClassPool classPool = ClassPool.getDefault();
- // 获取指定的类型
- CtClass ctClass = classPool.get("java.lang.String");
- System.out.println(ctClass.getName()); // 获取类名
- System.out.println("\tpackage " + ctClass.getPackageName()); // 获取包名
- System.out.print("\t" + Modifier.toString(ctClass.getModifiers()) + " class " + ctClass.getSimpleName()); // 获取限定符和简要类名
- System.out.print(" extends " + ctClass.getSuperclass().getName()); // 获取超类
- // 获取接口
- if (ctClass.getInterfaces() != null) {
- System.out.print(" implements ");
- boolean first = true;
- for (CtClass c : ctClass.getInterfaces()) {
- if (first) {
- first = false;
- } else {
- System.out.print(", ");
- }
- System.out.print(c.getName());
- }
- }
- System.out.println();
- }
修改类方法
- @Test
- public void test() throws Exception {
- // 获取本地类加载器
- ClassLoader classLoader = getLocaleClassLoader();
- // 获取要修改的类
- Class<?> clazz = classLoader.loadClass("edu.alvin.reflect.TestLib");
- // 实例化类型池对象
- ClassPool classPool = ClassPool.getDefault();
- // 设置类搜索路径
- classPool.appendClassPath(new ClassClassPath(clazz));
- // 从类型池中读取指定类型
- CtClass ctClass = classPool.get(clazz.getName());
- // 获取String类型参数集合
- CtClass[] paramTypes = {classPool.get(String.class.getName())};
- // 获取指定方法名称
- CtMethod method = ctClass.getDeclaredMethod("show", paramTypes);
- // 赋值方法到新方法中
- CtMethod newMethod = CtNewMethod.copy(method, ctClass, null);
- // 修改源方法名称
- String oldName = method.getName() + "$Impl";
- method.setName(oldName);
- // 修改原方法
- newMethod.setBody("{System.out.println(\"执行前\");" + oldName + "($$);System.out.println(\"执行后\");}");
- // 将新方法添加到类中
- ctClass.addMethod(newMethod);
- // 加载重新编译的类
- clazz = ctClass.toClass(); // 注意,这一行会将类冻结,无法在对字节码进行编辑
- // 执行方法
- clazz.getMethod("show", String.class).invoke(clazz.newInstance(), "hello");
- ctClass.defrost(); // 解冻一个类,对应freeze方法
- }
动态创建类
- @Test
- public void test() throws Exception {
- ClassPool classPool = ClassPool.getDefault();
- // 创建一个类
- CtClass ctClass = classPool.makeClass("edu.alvin.reflect.DynamiClass");
- // 为类型设置接口
- //ctClass.setInterfaces(new CtClass[] {classPool.get(Runnable.class.getName())});
- // 为类型设置字段
- CtField field = new CtField(classPool.get(String.class.getName()), "value", ctClass);
- field.setModifiers(Modifier.PRIVATE);
- // 添加getter和setter方法
- ctClass.addMethod(CtNewMethod.setter("setValue", field));
- ctClass.addMethod(CtNewMethod.getter("getValue", field));
- ctClass.addField(field);
- // 为类设置构造器
- // 无参构造器
- CtConstructor constructor = new CtConstructor(null, ctClass);
- constructor.setModifiers(Modifier.PUBLIC);
- constructor.setBody("{}");
- ctClass.addConstructor(constructor);
- // 参数构造器
- constructor = new CtConstructor(new CtClass[] {classPool.get(String.class.getName())}, ctClass);
- constructor.setModifiers(Modifier.PUBLIC);
- constructor.setBody("{this.value=$1;}");
- ctClass.addConstructor(constructor);
- // 为类设置方法
- CtMethod method = new CtMethod(CtClass.voidType, "run", null, ctClass);
- method.setModifiers(Modifier.PUBLIC);
- method.setBody("{System.out.println(\"执行结果\" + this.value);}");
- ctClass.addMethod(method);
- // 加载和执行生成的类
- Class<?> clazz = ctClass.toClass();
- Object obj = clazz.newInstance();
- clazz.getMethod("setValue", String.class).invoke(obj, "hello");
- clazz.getMethod("run").invoke(obj);
- obj = clazz.getConstructor(String.class).newInstance("OK");
- clazz.getMethod("run").invoke(obj);
- }
创建代理类
- @Test
- public void test() throws Exception {
- // 实例化代理类工厂
- ProxyFactory factory = new ProxyFactory();
- //设置父类,ProxyFactory将会动态生成一个类,继承该父类
- factory.setSuperclass(TestProxy.class);
- //设置过滤器,判断哪些方法调用需要被拦截
- factory.setFilter(new MethodFilter() {
- @Override
- public boolean isHandled(Method m) {
- return m.getName().startsWith("get");
- }
- });
- Class<?> clazz = factory.createClass();
- TestProxy proxy = (TestProxy) clazz.newInstance();
- ((ProxyObject)proxy).setHandler(new MethodHandler() {
- @Override
- public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
- //拦截后前置处理,改写name属性的内容
- //实际情况可根据需求修改
- System.out.println(thisMethod.getName() + "被调用");
- try {
- Object ret = proceed.invoke(self, args);
- System.out.println("返回值: " + ret);
- return ret;
- } finally {
- System.out.println(thisMethod.getName() + "调用完毕");
- }
- }
- });
- proxy.setName("Alvin");
- proxy.setValue("1000");
- proxy.getName();
- proxy.getValue();
- }
其中,TestProxy类内容如下:
- public class TestProxy {
- private String name;
- private String value;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getValue() {
- return value;
- }
- public void setValue(String value) {
- this.value = value;
- }
- }
获取方法名称
- @Test
- public void test() throws Exception {
- // 获取本地类加载器
- ClassLoader classLoader = getLocaleClassLoader();
- // 获取要修改的类
- Class<?> clazz = classLoader.loadClass("edu.alvin.reflect.TestLib");
- // 实例化类型池
- ClassPool classPool = ClassPool.getDefault();
- classPool.appendClassPath(new ClassClassPath(clazz));
- CtClass ctClass = classPool.get(clazz.getName());
- // 获取方法
- CtMethod method = ctClass.getDeclaredMethod("show", ObjectHelper.argumentsToArray(CtClass.class, classPool.get("java.lang.String")));
- // 判断是否为静态方法
- int staticIndex = Modifier.isStatic(method.getModifiers()) ? 0 : 1;
- // 获取方法的参数
- MethodInfo methodInfo = method.getMethodInfo();
- CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
- LocalVariableAttribute localVariableAttribute = (LocalVariableAttribute)codeAttribute.getAttribute(LocalVariableAttribute.tag);
- for (int i = 0; i < method.getParameterTypes().length; i++) {
- System.out.println("第" + (i + 1) + "个参数名称为: " + localVariableAttribute.variableName(staticIndex + i));
- }
- }
关于“获取方法名称”,其主要作用是:当Java虚拟机加载.class文件后,会将类方法“去名称化”,即丢弃掉方法形参的参数名,而是用形参的序列号来传递参数。如果要通过Java反射获取参数的参数名,则必须在编辑是指定“保留参数名称”。Javassist则不存在这个问题,对于任意方法,都能正确的获取其参数的参数名。
Javassist字节码增强示例的更多相关文章
- JVM插庄之一:JVM字节码增强技术介绍及入门示例
字节码增强技术:AOP技术其实就是字节码增强技术,JVM提供的动态代理追根究底也是字节码增强技术. 目的:在Java字节码生成之后,对其进行修改,增强其功能,这种方式相当于对应用程序的二进制文件进行修 ...
- 字节码增强技术-Byte Buddy
本文转载自字节码增强技术-Byte Buddy 为什么需要在运行时生成代码? Java 是一个强类型语言系统,要求变量和对象都有一个确定的类型,不兼容类型赋值都会造成转换异常,通常情况下这种错误都会被 ...
- 深入浅出Java探针技术1--基于java agent的字节码增强案例
Java agent又叫做Java 探针,本文将从以下四个问题出发来深入浅出了解下Java agent 一.什么是java agent? Java agent是在JDK1.5引入的,是一种可以动态修改 ...
- 从底层入手,解析字节码增强和Btrace应用
这篇文章聊下字节码和相关的应用. 1.机器码和字节码 机器码(machine code),学名机器语言指令,有时也被称为原生码(Native Code),是电脑的CPU可直接解读的数据. 通常意义上来 ...
- Java字节码增强技术
简单介绍下几种java字节码增强技术. ASM ASM是一个Java字节码操控框架,它能被用来动态生成类或者增强既有类的功能.ASM可以直接产生class文件,也可以在类被加载入Java虚拟机之前动态 ...
- 字节码增强-learnning
jvm加载java的过程主要是: 编写java文件->进行java文件的编译->生成.class字节码文件->jvm通过类加载器去加载生成的二进制文件 java编译器将源码文件编译称 ...
- Javassist 字节码 语法 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- JVM——字节码增强技术简介
Java字节码增强指的是在Java字节码生成之后,对其进行修改,增强其功能,这种方式相当于对应用程序的二进制文件进行修改.Java字节码增强主要是为了减少冗余代码,提高性能等. 实现字节码增强的主要步 ...
- SpringAOP之CGLIB字节码增强
SpringAOP的基础原理就是动态代理 有两种实现方式:1)jdk动态代理 2)cglib动态代理 jdk动态代理和cglib动态代理的区别在于: cglib没有接口(通过继承父类) 只有实现类. ...
随机推荐
- SpriteBuilder使用Shader Effect的另一种方法
记住你并不是必须要使用Effect节点去给一个特定的精灵应用效果. 你只要选择一个精灵然后切换至项目属性窗口(Item Properties tab),找到effects用户接口在CCSprite属性 ...
- 【一天一道LeetCode】#26. Remove Duplicates from Sorted Array
一天一道LeetCode系列 (一)题目 Given a sorted array, remove the duplicates in place such that each element app ...
- 【Qt编程】Qt 小时钟
Hello World! 学习编程语言的最简单最经典的小程序,当然Qt也不例外.在学习画图时,我觉得写个时钟小程序也是个比较好的开始.在之前的<Matlab及Java小时>一文中,我也从写 ...
- Make3D Convert your image into 3d model
Compiling and Running Make3D on your own computer source: http://make3d.cs.cornell.edu/code_linux.ht ...
- django-debug-tools 使用
用django开发很快也很容易,但是很多时候我们的经验并不是很足,就会给自己挖下很多坑,不管是性能问题,还是开发语言使用技巧问题都会给应用的稳定带来危害, 开发之后的调试和调优就显得很重要,今天就尝试 ...
- 面试之路(16)-归并排序详解(MergeSort)递归和非递归实现
归并排序的概念及定义 归并排序(Merge)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并排序是建立 ...
- python笔记--1
pip工具常用命令: pip命令示例 说明 pip download SomePackage[==version] 下载扩展库的指定版本,不安装 pip freeze [> requiremen ...
- Spring Boot Kafka
1.创建集群 http://kafka.apache.org/documentation/#quickstart 有一句我觉得特别重要: For Kafka, a single broker is j ...
- 途牛java实习面试(失败)
一进去让自己介绍.简单介绍了一下.然后让我自己说说框架.问题太大一紧张卡住了. 然后面试官开始问,让我介绍多线程,我就简单介绍了多线程.然后问我有没有做过多线程的项目,我说没有. 问了MySQL的锁和 ...
- 如何成为一个优秀的DBA
今天在群上跟技术友们聊天.发现有几个大学生,他们很担心自己找不到工作.我问他们理由,他们说我们没有经验,公司不要怎么办?这些孩子们的担心,让我感觉到奇怪. 如果我是一个公司的老总,我会有这两种考虑:要 ...