Java 中实现agent 中对类的修改 实际上是要实现instrument 包下的 ClassFileTransformer 接口并实现。
transform 方法 对类 或方法 进行修改,我们这里采用 字节码修改工具来实现对agent 功能的增强。
注意 (ClassFileTransformer需要添加到Instrumentation实例中才能生效,因此要想自定义去修改类,参考↓)
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("this is an perform monitor agent.");
// 自定义 ClassFileTransformer类型的 PerformMonitorTransformer 加入到 Instrumentation 中 ClassFileTransformer transformer = new PerformMonitorTransformer();
inst.addTransformer(transformer);
}
transform 方法
@Override
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer throws IllegalClassFormatException {}
}
返回的 byte[] 类型的的数据 就是返回的你 修改后的类的字节数组。如果懂的字节码,可以去直接修改,也可以利用字节码工具。 如: javassist asm。
使用 byte buddy 的字节码工具的在生成agent方面 也是底层还是封装了上述的 ClassFileTransformer 中的transform()。
Java 中实现 agent 的方式就这样加上之前总结的 instrument 类也就是说instrument 还有 byte buddy 都还有很多用法等着去发现。
试想
获得类加载器
根据类的注解 来
委托具体方法 。
因为接下来项目还要用到 byte buddy 这个工具因此 要展开学习一下它。
一:创建一个类
DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.name("example.Type") //NamingStrategy 未命名 默认会随机生成类名
.make();
System.out.println(dynamicType.getClass());
可以看到 Unloaded 没有进行加载,运行main 方法自己定义的 name名称没有打印 只是打印了所处的位置
Class<?> dynamicType1 = new ByteBuddy()
.subclass(Object.class)
.name("example.Type") //NamingStrategy 未命名 默认会随机生成类名
.make()
.load(getClass().getClassLoader(),ClassLoadingStrategy.Default.WRAPPER).getLoaded();
System.out.println(dynamicType1);
指定类加载器进行类加载到jvm 此时自己定义的 name 生效,代表着创建一个类成功。
new ByteBuddy()的配置参数
.subclass(父类名 要实现的类名)
.name("自定义设置类名")
.load()//进行类加载
.method(named("foo")).intercept(FixedValue.value("Two!")) 进行方法的修改
.intercept() // 进行方法的委托
在JavaAgent 中 使用byte buddy 来完成对java agent 的操作
用 agentBuilder 来使用Byte buddy方式
对填有注解的方法 进行 agent 的功能操作。
agentBuilder = agentBuilder
.type(nameMatches(entry.getKey()))
.transform(getForAdvice(classLoaderCache).advice(ElementMatchers.isAnnotatedWith(ElementMatchers.named(method)),CustomPromagentAdvice.class.getName()));
其中 type() 来匹配类型
transform() 通过底层instrument 的方法来实现对类的 advice (要注解的方法,实现advice的类)去对注解方法匹配的进行 agent aop 的功能。
通过 OnMethodEnter 注解 及 OnMethodExit 注解来 实现对要进行 字节码改变的方法。
ElementMatchers.nameMatches("xxx") // 根据名称去匹配
ElementMatchers.isAnnotatedWith(ElementMatchers.named(method))// 根据匹配注解
所以 Java agent 的这个技术 完全可以用在 在运行前去实现一些功能,当作程序运行期间的守护进程,我们是用到了较为 高级的agent 的使用方式 结合字节码修改工具对 修改类的的从而实现aop的 用途,但如果只是要当作守护进程或者监视进程,也可以通过新开一个线程的方式进行。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。