替换类实现

maven 引入

  [xml]
1
2
3
4
5
6
7
8
9
10
11
12
<dependencies> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> <version>1.8.0</version> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> <version>1.8.0</version> </dependency> </dependencies>

测试类定义

  • Log.java
  [java]
1
2
3
4
5
6
7
8
public class Log { public static void log(String a) { System.out.println("Log: " + a); } }
  • Log4j.java
  [java]
1
2
3
4
5
6
7
8
9
10
11
public class Log4j { /** * 注意代理类要和原实现类的方法声明保持一致 * @param a */ public static void log(String a) { System.err.println("Log4j: " + a); } }

替换测试

  • main()

将 log 的实现替换为 log4j

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import net.bytebuddy.ByteBuddy; import net.bytebuddy.agent.ByteBuddyAgent; import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.matcher.ElementMatchers; public class LogMain { public static void main(String[] args) { // 替换 ByteBuddyAgent.install(); new ByteBuddy().redefine(Log.class) .method(ElementMatchers.named("log")) .intercept(MethodDelegation.to(Log4j.class)) .make() .load(Thread.currentThread().getContextClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); // 调用 Log.log("hello"); } }
  • 日志输出
  [java]
1
Log4j: hello

个人感受

比起 spring aop,感觉依赖更少,也更加优雅。

参考资料

基于 ByteBuddy 运行时动态修改字节码