-
官网
-
github
-
作用
-
简单使用案例
-
依赖
-
动态生成接口的实现
-
对方法作代理增强
官网
https://www.javassist.org/
github
https://github.com/jboss-javassist/javassist
作用
简单来说Javassist主要用于操作Java字节码,让我们操作字节码变得简单,可以在JVM加载类文件的时候去修改它。与其他字节码编辑器不同的是Javassist提供了两个级别的API,源代码级和字节码级。如果用户使用源级 API,他们可以在不了解 Java 字节码规范的情况下编辑类文件。目前自己应用到的场景有如下:
-
动态加载实现接口的实现类 -
动态增强原有类的方法
简单使用案例
依赖
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-GA</version>
</dependency>
动态生成接口的实现
首先定义一个接口
public interface IHello {
void sayHello(String name, Integer age);
}
动态生成接口实现类并调用
public class Proxy<T> {
/**
* 接口
*/
private Class<T> t;
public Proxy(Class<T> t){
this.t = t;
}
/**
* 生成的代理对象名称前缀
*/
private static final String PROXYFREFIX = "$Proxy";
/**
* 生成的代理对象名称前缀
*/
private static final String PROXYSUFFIX = "Impl";
/*对接口--IHello进行增强,添加方法体*/
public static void main(String[] args) throws Exception{
ClassPool pool = ClassPool.getDefault();
//接口实现类的名字
Proxy<IHello> proxy = new Proxy<>(IHello.class);
String clazzName = proxy.getPackageName() + proxy.getProxyObjectName();
System.out.println("clazzName: " + clazzName);
// 创建实现类 = public class com.test.cider.javassist$ProxyIHelloImpl {}
CtClass targetClass = pool.makeClass(clazzName);
//获得接口的CtClass IHello.class.getName() = proxy.t.getClass().getName()
CtClass interf = pool.getCtClass(IHello.class.getName());
CtClass[] interfs = new CtClass[]{interf};
// 这行代码等 = public class ProxyIHelloImpl implements IHello{}
targetClass.setInterfaces(interfs);
// 获取接口 sayHello 方法
CtMethod method = interf.getDeclaredMethod("sayHello");
// 创建方法
CtMethod m = new CtMethod(method.getReturnType(),method.getName(),method.getParameterTypes(),targetClass);
//设置方法的实现类
// System.out.println("姓名: " + $1 + " 年龄: " + $2);
m.setBody(" System.out.println("姓名: " + $1 + " 年龄: " + $2);n");
targetClass.addMethod(m);
//生成Class文件
// targetClass.writeFile("C:\Users\java\src\main\resources");
//生成Class载入内存
Class<?> target = targetClass.toClass();
//实例化
IHello o = (IHello) target.getDeclaredConstructor().newInstance();
o.sayHello("weihubeats", 18);
}
//获取包名
public String getPackageName(){
Package aPackage = t.getPackage();
return aPackage.getName();
}
//获取代理对象的名称
public String getProxyObjectName(){
return PROXYFREFIX+t.getSimpleName()+PROXYSUFFIX;
}
}
实际效果

对方法作代理增强
首先写一个需要增强的方法
public class JavassistTest {
public String sayHello(String a) {
System.out.println("原来方法也执行了,参数: " + a);
return "1223";
}
}
然后对原有方法进行增强
public class Test {
public static void sayHello(String aa) {
System.out.println("增强" + aa);
}
public static void main(String[] args) throws Exception{
CtClass cc;
ClassPool pool = ClassPool.getDefault();
cc = pool.get("com.test.cider.javassist.JavassistTest");
CtMethod ctMethod = cc.getDeclaredMethod("sayHello");
ctMethod.insertBefore("com.test.cider.javassist.Test.sayHello($1);");
cc.toClass();
JavassistTest javassistTest = new JavassistTest();
javassistTest.sayHello("haha");
}
}
原文始发于微信公众号(小奏技术):字节码技术 Javassist的学习使用(动态加载接口实现类,AOP原理)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/30251.html