折腾了好久的javaagent不知为何就是不能在load类的时候进行其他类的执行,先放一放,了解一下ByteBuddy的使用
Byte Buddy 是一个代码生成和操作库,用于在Java应用程序运行时创建和修改Java类,而无需编译器的帮助。除了Java类库附带的代码生成实用程序外,Byte Buddy还允许创建任意类,并且不限于实现用于创建运行时代理的接口。此外,Byte Buddy提供了一种方便的API,可以使用Java代理或在构建过程中手动更改类。
比起javassist,asm,bcel起来都比较简单
个人理解就是为了解决Java静态语言的不方便之处,通过直接生成字节码然后使用JVM运行,和反射机制有点像,但是比反射机制效率更高,因为是生成字节码直接跑java虚拟机。
首先安装
maven的项目在pom.xml里面添加一个依赖
1 2 3 4 5
| <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> <version>1.12.2</version> </dependency>
|
看看用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.iast;
import net.bytebuddy.ByteBuddy; import net.bytebuddy.implementation.FixedValue; import net.bytebuddy.matcher.ElementMatchers;
public class MyAgent {
public static void main(String[] args) throws InstantiationException, IllegalAccessException { Class<?> dynamicType = new ByteBuddy().subclass(Object.class).method(ElementMatchers.named("toString")) .intercept(FixedValue.value("Hello World")).make().load(MyAgent.class.getClassLoader()).getLoaded();
Object instance = dynamicType.newInstance(); String toString = instance.toString(); System.out.println(toString); System.out.println(instance.getClass().getCanonicalName()); }
}
|
完成动态构造一个类并且输出他的
- subclass指定了新创建类的父类
- method指定了Object的处理方法
- intercept拦截了toString方法并返回指定的helllo world
- 最后make产生字节码,由类加载器加载到虚拟机中
创建类
1 2 3
| DynamicType.Unloaded<?> dynamicType = new ByteBuddy() .subclass(Object.class) .make();
|
创建一个类,还可以在make生成字节码之前.name("your_name")
来进行命名
加载类
1 2 3 4 5
| Class<?> type = new ByteBuddy() .subclass(Object.class) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded();
|
redefine和rebase
redefine修改之后就会把原来的类功能冲掉,变得不可用
rebase只是加了个前缀而已
重载类
相当于是和javaagent一样的功能,在类load的时候劫持并且运行我们自己的类
1 2 3 4 5 6 7
| class Foo { String m() { return "foo"; } } class Bar { String m() { return "bar"; } }
|
1 2 3 4 5 6 7 8
| ByteBuddyAgent.install(); Foo foo = new Foo(); new ByteBuddy() .redefine(Bar.class) .name(Foo.class.getName()) .make() .load(Foo.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); assertThat(foo.m(), is("bar"));
|
方法拦截
1 2 3 4 5 6 7 8 9 10 11 12
| Foo dynamicFoo = new ByteBuddy() .subclass(Foo.class) .method(isDeclaredBy(Foo.class)).intercept(FixedValue.value("One!")) .method(named("foo")).intercept(FixedValue.value("Two!")) .method(named("foo").and(takesArguments(1))).intercept(FixedValue.value("Three!")) .make() .load(getClass().getClassLoader()) .getLoaded() .newInstance();
|
参考
https://bytebuddy.net/#/tutorial