折腾了好久的javaagent不知为何就是不能在load类的时候进行其他类的执行,先放一放,了解一下ByteBuddy的使用
Byte Buddy 是一个代码生成和操作库,用于在Java应用程序运行时创建和修改Java类,而无需编译器的帮助。除了Java类库附带的代码生成实用程序外,Byte Buddy还允许创建任意类,并且不限于实现用于创建运行时代理的接口。此外,Byte Buddy提供了一种方便的API,可以使用Java代理或在构建过程中手动更改类。
比起javassist,asm,bcel起来都比较简单
个人理解就是为了解决Java静态语言的不方便之处,通过直接生成字节码然后使用JVM运行,和反射机制有点像,但是比反射机制效率更高,因为是生成字节码直接跑java虚拟机。
首先安装
maven的项目在pom.xml里面添加一个依赖
| 12
 3
 4
 5
 
 | <dependency><groupId>net.bytebuddy</groupId>
 <artifactId>byte-buddy</artifactId>
 <version>1.12.2</version>
 </dependency>
 
 | 
看看用法
| 12
 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产生字节码,由类加载器加载到虚拟机中
创建类
| 12
 3
 
 | DynamicType.Unloaded<?> dynamicType = new ByteBuddy().subclass(Object.class)
 .make();
 
 | 
创建一个类,还可以在make生成字节码之前.name("your_name")来进行命名
加载类
| 12
 3
 4
 5
 
 | Class<?> type = new ByteBuddy().subclass(Object.class)
 .make()
 .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
 .getLoaded();
 
 | 
redefine和rebase
redefine修改之后就会把原来的类功能冲掉,变得不可用
rebase只是加了个前缀而已
重载类
相当于是和javaagent一样的功能,在类load的时候劫持并且运行我们自己的类
| 12
 3
 4
 5
 6
 7
 
 | class Foo {String m() { return "foo"; }
 }
 
 class Bar {
 String m() { return "bar"; }
 }
 
 | 
| 12
 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"));
 
 | 
方法拦截
| 12
 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