前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java agent和byte-buddy组合的简单使用

java agent和byte-buddy组合的简单使用

作者头像
路行的亚洲
发布2024-02-17 15:32:21
3820
发布2024-02-17 15:32:21
举报
文章被收录于专栏:后端技术学习后端技术学习

一、java agent和byte-buddy组合的使用场景

java agent开了一扇门,bytebuddy在开的这扇门中打开了一片新的天地。比较典型的就是skywalking、sermant、arthas、mockito、fastjson等。是不是很好奇skywalking、sermant、arthas、mockito、fastjson的原理。下面我们来了解一下。

二、Java Agent技术的框架

Java Agent技术是一种在Java虚拟机(JVM)启动时或运行时,可以插入到JVM中的程序。这种技术主要用于实现一些高级功能,如字节码操作、性能监控、调试、热修复等。

在Java Agent技术的框架下,常用的框架有以下几个:

  1. Byte Buddy: 这是一个强大的库,用于在运行时创建和修改Java类。Byte Buddy提供了一个简单易用的API,用于生成、修改和加载Java字节码。它支持Java 5及更高版本,并且与Java Agent技术非常配合。
  2. ASM: ASM是一个Java字节码操控框架。它能直接生成或以二进制形式修改已有类或者核心类的字节码。ASM可以直接生成字节码,而不需要了解Java虚拟机指令。ASM比其他的Java字节码操控框架(例如Javassist, BCEL, CGLIB)更快更小。
  3. Javassist: Javassist是一个开源的分析、编辑和创建Java字节码的库。它已经被许多其他的Java类库和工具使用,包括Hibernate和Spring。Javassist是分析字节码的工具,并且提供了一个简单的API来操作和生成字节码。
  4. Instrumentation API: 这是Java Agent技术的核心API,用于在运行时修改类的字节码。使用这个API,你可以实现自己的类加载器,并在类被加载到JVM时修改其字节码。
  5. HotSwapAgent: HotSwapAgent是一个Java类重新加载器,它支持在不停止和重启JVM的情况下重新加载已修改的类。HotSwapAgent基于Java Instrumentation API,并提供了更多的功能,如条件断点、类变量查看和修改等。

三、基于java agent和byte-buddy组合简单使用

首先需要准备好premain,然后基于premain中定义的转换器,在转换器中,添加需要拦截的方法,拦截的规则,最终将其安装到Instrumentation。

1)首先准备好java agent的premain
代码语言:javascript
复制
public class PreMainAgent {

    public static void premain(String agentArgs, Instrumentation inst) {
        //创建一个转换器,转换器可以修改类的实现
        //ByteBuddy对java agent提供了转换器的实现,直接使用即可
        AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
            public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule) {
                return builder
                        // 拦截任意方法
                        .method(ElementMatchers.<MethodDescription>any())
                        // 拦截到的方法委托给TimeInterceptor
                        .intercept(MethodDelegation.to(MyInterceptor.class));
            }
        };
         new AgentBuilder 
                .Default()
                // 根据包名前缀拦截类
                .type(ElementMatchers.nameStartsWith("com.agent"))
                // 拦截到的类由transformer处理
                .transform(transformer)
                .installOn(inst);
    }
}
2)在pom.xml中新增premain的信息
代码语言:javascript
复制
<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <appendAssemblyId>false</appendAssemblyId>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <archive> <!--自动添加META-INF/MANIFEST.MF -->
            <manifest>
                <!-- 添加 mplementation-*和Specification-*配置项-->
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
            <manifestEntries>
                <!--指定premain方法所在的类-->
                <Premain-Class>com.example.demo.bytecode.PreMainAgent</Premain-Class>
                <!--添加这个即可-->
                <Agent-Class>com.example.demo.bytecode.PreMainAgent</Agent-Class>
                <Can-Redefine-Classes>true</Can-Redefine-Classes>
                <Can-Retransform-Classes>true</Can-Retransform-Classes>
            </manifestEntries>
        </archive>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>
3)准备好拦截器
代码语言:javascript
复制
public class MyInterceptor {
    @RuntimeType
    public static Object intercept(@Origin Method method,
                                   @SuperCall Callable<?> callable)
            throws Exception {
        long start = System.currentTimeMillis();
        try {
            //执行原方法
            return callable.call();
        } finally {
            //打印调用时长
            System.out.println(method.getName() + ":" + (System.currentTimeMillis() - start)  + "ms");
        }
    }
}

将其打好包,然后在业务系统中使用即可

4)在业务系统中引入byte-buddy的依赖
代码语言:javascript
复制
<dependencies>
    <dependency>
        <groupId>net.bytebuddy</groupId>
        <artifactId>byte-buddy</artifactId>
        <version>1.9.2</version>
    </dependency>
    <dependency>
        <groupId>net.bytebuddy</groupId>
        <artifactId>byte-buddy-agent</artifactId>
        <version>1.9.2</version>
    </dependency>
</dependencies>
5)在业务系统项目中使用

注意:这里的包应该是com.example.biz打头的

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Hello Byte-Buddy");
    }
}

以上是对byte-buddy的简单入门案例,通过上面的案例可以很好的理解sermant的原理。

参考:

byte-buddy开源地址:https://github.com/raphw/byte-buddy

sermant开源地址:https://github.com/huaweicloud/Sermant

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-02-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端技术学习 微信公众号,前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、java agent和byte-buddy组合的使用场景
  • 二、Java Agent技术的框架
  • 三、基于java agent和byte-buddy组合简单使用
    • 1)首先准备好java agent的premain
      • 2)在pom.xml中新增premain的信息
        • 3)准备好拦截器
          • 4)在业务系统中引入byte-buddy的依赖
            • 5)在业务系统项目中使用
            相关产品与服务
            应用性能监控
            应用性能监控(Application Performance Management,APM)是一款应用性能管理平台,基于实时多语言应用探针全量采集技术,为您提供分布式性能分析和故障自检能力。APM 协助您在复杂的业务系统里快速定位性能问题,降低 MTTR(平均故障恢复时间),实时了解并追踪应用性能,提升用户体验。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档