前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java agent 与 byte buddy

Java agent 与 byte buddy

原创
作者头像
猎户星座1
修改2020-08-11 10:22:55
1.8K0
修改2020-08-11 10:22:55
举报
文章被收录于专栏:Java StudyJava Study

Java 中实现agent 中对类的修改 实际上是要实现instrument 包下的 ClassFileTransformer 接口并实现。

transform 方法 对类 或方法 进行修改,我们这里采用 字节码修改工具来实现对agent 功能的增强。

 注意 (ClassFileTransformer需要添加到Instrumentation实例中才能生效,因此要想自定义去修改类,参考↓)

代码语言:javascript
复制
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 方法

代码语言:javascript
复制
@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

因为接下来项目还要用到 byte buddy 这个工具因此 要展开学习一下它。

一:创建一个类

代码语言:javascript
复制
DynamicType.Unloaded<?>  dynamicType = new ByteBuddy()
        .subclass(Object.class)
        .name("example.Type")   //NamingStrategy 未命名 默认会随机生成类名
        .make();
         System.out.println(dynamicType.getClass()); 

可以看到 Unloaded 没有进行加载,运行main 方法自己定义的 name名称没有打印 只是打印了所处的位置

代码语言:javascript
复制
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()//进行类加载

代码语言:javascript
复制
.method(named("foo")).intercept(FixedValue.value("Two!")) 进行方法的修改

.intercept()  // 进行方法的委托

在JavaAgent 中 使用byte buddy 来完成对java agent 的操作

用 agentBuilder 来使用Byte buddy方式

  对填有注解的方法 进行 agent 的功能操作。

代码语言:javascript
复制
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 注解来 实现对要进行 字节码改变的方法。

代码语言:javascript
复制
ElementMatchers.nameMatches("xxx")  // 根据名称去匹配
ElementMatchers.isAnnotatedWith(ElementMatchers.named(method))// 根据匹配注解  

所以 Java agent 的这个技术 完全可以用在 在运行前去实现一些功能,当作程序运行期间的守护进程,我们是用到了较为 高级的agent 的使用方式 结合字节码修改工具对 修改类的的从而实现aop的 用途,但如果只是要当作守护进程或者监视进程,也可以通过新开一个线程的方式进行。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • byte buddy
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档