Javassist简介
Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。它可以用来检查、”动态”修改以及创建 Java类。其功能与jdk自带的反射功能类似,但比反射功能更强大。
package com.javassis.test;
public class CoolGuy {
private String hotGirlfriendName;
private String niceCarModel;
public String getHotGirlfriendName() {
return hotGirlfriendName;
}
public void setHotGirlfriendName(String hotGirlfriendName) {
this.hotGirlfriendName = hotGirlfriendName;
}
public String getNiceCarModel() {
return niceCarModel;
}
public void setNiceCarModel(String niceCarModel) {
this.niceCarModel = niceCarModel;
}
}
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.javassis.test; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.Loader;
import javassist.NotFoundException; public class Main {
public static void main(String[] args) throws NotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
CannotCompileException, IOException, ClassNotFoundException {
ClassPool classPool = ClassPool.getDefault();
/**
* CoolGuy是已经存在的类
*/
CtClass ctc = classPool.get("com.javassis.test.CoolGuy");
Class<?> c = ctc.toClass();
Object cg = (Object) c.newInstance();
Method m = c.getDeclaredMethod("setHotGirlfriendName", String.class);
m.invoke(cg, "柳岩");
System.out.println("CoolGuy's girlfriend is " + ((CoolGuy) cg).getHotGirlfriendName());
/**
* 动态构造一个SuckGuy类
*/
CtClass suckCt = classPool.makeClass("com.javassis.test.SuckGuy");
// 添加域
CtField girlfriendField = new CtField(classPool.get("java.lang.String"), "hotGirlfriendName", suckCt);
CtField carField = new CtField(classPool.get("java.lang.String"), "niceCarModel", suckCt);
suckCt.addField(girlfriendField);
suckCt.addField(carField);
// 添加方法
CtMethod getMethod = CtNewMethod.make("public String getHotGirlfriendName() { return this.hotGirlfriendName;}",
suckCt);
CtMethod setMethod = CtNewMethod
.make("public void setHotGirlfriendName(String girl) { this.hotGirlfriendName = girl;}", suckCt);
suckCt.addMethod(getMethod);
suckCt.addMethod(setMethod);
getMethod = CtNewMethod.make("public String getNiceCarModel() { return this.niceCarModel;}", suckCt);
setMethod = CtNewMethod
.make("public void setNiceCarModel(String niceCarModel) { this.niceCarModel = niceCarModel;}", suckCt);
suckCt.addMethod(getMethod);
suckCt.addMethod(setMethod);
Class<?> cuckClass = suckCt.toClass();
Object suckGuy = cuckClass.newInstance();
m = cuckClass.getDeclaredMethod("setHotGirlfriendName", String.class);
m.invoke(suckGuy, "凤姐");
String suckGirlfriend = (String) cuckClass.getMethod("getHotGirlfriendName", null).invoke(suckGuy, null);
System.out.println("SuckGuy's girlfriend is " + suckGirlfriend);
/**
* 设置CoolGuy父类为Person
*/
//ctc.writeFile();
ctc.defrost(); // 先解冻,不然会报class is frozen异常,
// CtClass对象通过writeFile()、toClass()、toBytecode()转化为Class后,Javassist冻结了CtClass对象,因此,JVM不允许再次加载Class文件,所以不允许对其修改
ctc.setSuperclass(classPool.get("com.javassis.test.Person"));
Loader cl = new Loader(classPool);// 同一个classloader下不能加载两次class,所以新new一个loader
// c = ctc.toClass();
c = cl.loadClass("com.javassis.test.CoolGuy");
cg = (Object) c.newInstance();
m = c.getMethod("setAge", int.class);
m.invoke(cg, 25);
m = c.getMethod("getAge", null);
System.out.println("CoolGuy's age is " + m.invoke(cg, null));
}
}
输出:
CoolGuy's girlfriend is 柳岩
SuckGuy's girlfriend is 凤姐
CoolGuy's age is 25
几个需要注意的地方:
1、笔者用的Javassist版本是3.22.0-GA,比较坑爹的是它必须使用java 9,笔者一开始用java 8会报java.lang.NoClassDefFoundError: java/lang/StackWalker$Option
2、CtClass对象通过writeFile()、toClass()、toBytecode()转化为Class后,Javassist冻结了CtClass对象,因此,JVM不允许再次加载Class文件,所以不允许对其修改
,再次对其修改时需要defrost() 先解冻,不然会报class is frozen异常。
3、解冻后对类进行修改,之后使用修改后的类需要再次加载,此时虽然已经经过defrost() ,但同一个classloader下不能加载两次class,再次使用toClass()会报错,所以新new一个loader,使用loader.loadClass()完成Class加载。
接下来看看对如何动态的去修改类的方法:
思路就是把需要修改的方法改个新名字,然后新建一个新方法,名字命名为原名字,新方法copy原方法的内容并加入新的代码。
package com.javassis.test; import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod; /*
* 动态修改CoolGuy的一个方法
* */
public class UpdateTest {
public static void main(String[] args) throws Exception {
ClassPool classPool = ClassPool.getDefault();
CtClass ctc = classPool.get("com.javassis.test.CoolGuy");
String mName = "getHotGirlfriendName";
CtMethod m = ctc.getDeclaredMethod(mName);
m.setName(mName + "$old");
CtMethod nm = CtNewMethod.copy(m, mName, ctc, null);
StringBuffer mbody = new StringBuffer();
mbody.append("{");
mbody.append("\n return hotGirlfriendName");
mbody.append(" + \"和鞠婧祎\"; \n");
mbody.append("}");
nm.setBody(mbody.toString());
ctc.addMethod(nm);
Class<?> c = ctc.toClass();
CoolGuy coolGuy = (CoolGuy)c.newInstance();
coolGuy.setHotGirlfriendName("柳岩");
System.out.println("CoolGuy's girlfriend is " + coolGuy.getHotGirlfriendName());
}
}
运行结果:
CoolGuy's girlfriend is 柳岩和鞠婧祎
Javassist简介的更多相关文章
- java ----> 类转换异常
com.rr.domain.Department_$$_javassist_5 cannot be cast to javassist.util.proxy.Proxy 两个原因: 1.懒加载 在we ...
- Javassist 字节码 简介 案例 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...
- Java 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...
- javassist:字节码编辑器工具
简介: javassist是一款可以在运行时生成字节码的工具,可以通过它来构造一个新的class对象.method对象,这个class是运行时生成的.可以通过简短的几行代码就可以生成一个新的class ...
- dubbo使用简介
---------------------------------------------------------------------------------------------------- ...
- Javassist 字节码 语法 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Java动态代理机制详解(类加载,JDK 和CGLIB,Javassist,ASM)
class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...
- 设计模式7---Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...
随机推荐
- Swift 项目中可能用到的第三方框架
这里记录下swift开发中可能用的框架 , 最近浏览了不少,积累在这里,以后用的时候方便查阅.顺便推荐给大家! 这里的框架都是纯swift的 , 感谢开源 ,感谢大神们 . 下拉刷新 BreakOut ...
- Combobox实现多项选择 Silverlight下“Combobox”怎样实现多项选择?
把 combobox里面的项换成checkedbox 示例: combobox cbb=new combobox(); ) { CheckBox cb = new CheckBox(); cb.Com ...
- RNA-seq要做几次生物学重复?找出来的100%都是真正的应答基因
尹师妹:“哈师兄,做验证实验好辛苦,老板让我提高筛选差异基因的条件,尽量降低假阳性,我该怎么筛?” 小哈打开Evernote,给尹师妹看张表: “瞧见那个100%了吗?30 million mappe ...
- $.fn.extend 和$.extend函数
区别和详解:jQuery extend()和jQuery.fn.extend() 首先是简单的概述区别:$.extend()是类方法 $.fn.extend()是原型方法 对象方法和原 ...
- CountVectorizer()类解析
主要可以参考下面几个链接: 1.sklearn文本特征提取 2.使用scikit-learn tfidf计算词语权重 3.sklearn官方中文文档 4.sklearn.feature_extra ...
- 643. Maximum Average Subarray I
static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...
- 557. Reverse Words in a String III
static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...
- 2018.10.23 NOIP训练 Leo的组合数问题(组合数学+莫队)
传送门 好题. 考察了莫队和组合数学两个知识板块. 首先需要推出单次已知n,mn,mn,m的答案的式子. 我们令f[i]f[i]f[i]表示当前最大值为第iii个数的方案数. 显然iii之后的数都是单 ...
- 2018.09.28 hdu5434 Peace small elephant(状压dp+矩阵快速幂)
传送门 看到n的范围的时候吓了一跳,然后发现可以矩阵快速幂优化. 我们用类似于状压dp的方法构造(1(1(1<<m)∗(1m)*(1m)∗(1<<m)m)m)大小的矩阵. 然后 ...
- 2018.09.12 poj3621Sightseeing Cows(01分数规划+spfa判环)
传送门 01分数规划板题啊. 发现就是一个最优比率环. 这个直接二分+spfa判负环就行了. 代码: #include<iostream> #include<cstdio> # ...