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没有接口(通过继承父类) 只有实现类. ...
随机推荐
- 2014新年福利,居然有人将Ext JS 4.1的文档翻译了
原文:http://damoqiongqiu.iteye.com/blog/1998022
- Android NFC开发(二)——Android世界里的NFC所具备的条件以及使用方法
Android NFC开发(二)--Android世界里的NFC所具备的条件以及使用方法 NFC的应用比较广泛,而且知识面也是比较广的,所以就多啰嗦了几句,我还还是得跟着官方文档:http://dev ...
- Android特效专辑(十)——点击水波纹效果实现,逻辑清晰实现简单
Android特效专辑(十)--点击水波纹效果实现,逻辑清晰实现简单 这次做的东西呢,和上篇有点类似,就是用比较简单的逻辑思路去实现一些比较好玩的特效,最近也是比较忙,所以博客更新的速度还得看时间去推 ...
- 【55】java异常机制剖析
一.为什么要使用异常 首先我们可以明确一点就是异常的处理机制可以确保我们程序的健壮性,提高系统可用率.虽然我们不是特别喜欢看到它,但是我们不能不承认它的地位,作用.有异常就说明程序存在问题,有助于我们 ...
- Redis配置信息
# Redis configuration file example # Note on units: when memory size is needed, it is possible to sp ...
- java的finalize方法使用
1. finalize的作用 finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法. finalize()与C++中的析构函数 ...
- 《MySQL必知必会》读书笔记_2
通配符:(尾空格可能会干扰通配符匹配) % 匹配任意字符 _ 匹配任意单个字符 正则表达式:REGEXP 用法就是替换掉LIKE的位置,后面配合正则表达式. 默认不区分大小写,如果区分的话添加关键字B ...
- win8 JDK环境变量不生效
执行where java 看一下路径对不对,如果对的话就把system32下面的3个java相关的exe删了即可,如果路径不对就修改环境变量.
- access按钮事件在子窗体打开窗体或报表
Private Sub Com1_Click()Me.win.SourceObject = "窗体1"End Sub Private Sub Com2_Click()Me.win. ...
- DjangoRestFramework实践笔记
1.Restful服务的实现方式一共三种:function based view,class based view,viewset+router,这三种实现方式的封装重度依序升高,越往后越适合典型CU ...