0、基本概念
class文件随着虚拟机启动的时候,会经过premain方法,premain方法中定义了transform,这个premain在虚拟机启动的时候会被执行一次,然后通过transform方法对类进行了修饰,就好像被穿了一件衣服,class加载的时候注入了transform中的内容,以后每次class执行的时候就会走一次transform里面的东西,就好下你给之前给你穿了一个衣服,以后每次看你你都穿着这个衣服。
retransformClasses是因为agent虽然嵌入了,但是在虚拟机启动的时候,某些类比如thread,在javaagent启动之前就已经加载到了内存,javaagent也是类,在javaagent加载之前虚拟机需要加载一些必须的类来保证我的javaagent的运行,比如说thread,这个时候thread就没有被”穿上衣服“,即没有被transform修饰,也就不能被javaagent监控到,这个时候就需要retransformClasses重新加载,注意retransformClasses会让没有被”穿上衣服的类”穿上衣服“
redefineClasses也是重新加载一次,但是这里注意并没有给类”穿衣服“,即通过这种方法加载的时候,类不会经过transform方法。这个方法的作用类似于,原来给类”穿上了衣服“,通过这个方法可以给这个类”脱了衣服“
0.1、规则
- 添加多个transformer时,调用retransformClasses,则最后的transformer生效
- 添加transformer且retransformClasses之后,再添加transformer且retransformClasses,则后 面添加的transformer生效
- 添加两个transformer且都retransformClasses之后,删除最后添加的transformer,然后再retransformClasses,则第一个生效
1、main函数运行前加载
public static void premain(String agentArgs, Instrumentation inst)
public static void premain(String agentArgs)
1.1 使用方式
ClassFileTransformer transformer = new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
System.out.println("premain load Class:" + className);
return classfileBuffer;
}
};
注意:
1.2 通过bytebuddy使用
public class DemoAgent {
public static void premain(String arg, Instrumentation instrumentation) {
System.out.println("agent拦截开始");
Transformer transformer = new AgentBuilder.Transformer() {
@Override
public Builder<?> transform(Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader,
JavaModule module) {
return builder.method(ElementMatchers.named("toString"))
.intercept(MethodDelegation.to(MethodCostTime.class));
}
};
AgentBuilder.Listener listener = new AgentBuilder.Listener() {
@Override
public void onDiscovery(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
}
@Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
boolean loaded, DynamicType dynamicType) {
System.out.println(dynamicType.getTypeDescription().getActualName());
}
@Override
public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
boolean loaded) {
}
@Override
public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded,
Throwable throwable) {