Javassist

Javassist (Java Programming Assistant) makes Java bytecode manipulation simple. It is a class library for editing bytecodes in Java; it enables Java programs to define a new class at runtime and to modify a class file when the JVM loads it.

tutorial

Hello World

  • Import jar
  [xml]
1
2
3
4
5
<dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency>

Hello World

  • Util.java
  [java]
1
2
3
4
5
6
7
8
9
/** * 当工具类添加此注解。将其 constructor 默认 private{}; * Created by bbhou on 2017/9/29. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited public @interface Util { }
  • UtilInterceptor.java
  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/** * Util 注解解释器 * Created by bbhou on 2017/9/29. */ @Util public class UtilInterceptor { /** * 对类进行增强 * 1. 添加私有构造器 */ public static void enhance() { try { ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.getCtClass(UtilInterceptor.class.getName()); Util util = (Util) ctClass.getAnnotation(Util.class); if (util != null) { System.out.println("========================== 开始增强 =========================="); CtConstructor constructor = ctClass.getDeclaredConstructor(null); constructor.setModifiers(Modifier.PRIVATE); byte[] bytes = ctClass.toBytecode(); //1. 为方便此处路径写死,实际编写可动态获取 final String targetPath = "D:\\CODE\\paradise\\paradise-core\\target\\classes\\com\\ryo\\paradise\\core\\interceptor\\UtilInterceptor.class"; FileOutputStream fileOutputStream = new FileOutputStream(new File(targetPath)); fileOutputStream.write(bytes); fileOutputStream.flush(); fileOutputStream.close(); System.out.println("========================== 结束增强 =========================="); } } catch (NotFoundException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (CannotCompileException e) { e.printStackTrace(); } } }
  • SimpleTest.java
  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
public class SimpleTest { public static void main(String[] args) { //运行之后 class 内容会被修改 UtilInterceptor.enhance(); //第二次运行此处会报错 //Exception in thread "main" java.lang.IllegalAccessError: tried to access method com.ryo.paradise.core.interceptor.UtilInterceptor.<init>()V from class SimpleTest //at SimpleTest.main(SimpleTest.java:13) new UtilInterceptor(); } }

Thinking

使用这种修饰方式,比较适合运行时的增强。(spring 实现原理)

但是如果想实现编译时的修改,就需要借助 JCTree。(Java 编译原理)