首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >APM - Hello Javaagent

APM - Hello Javaagent

作者头像
小小工匠
发布2021-08-17 15:33:32
发布2021-08-17 15:33:32
9700
举报
文章被收录于专栏:小工匠聊架构小工匠聊架构

什么是javaagent

简单来说, javaagent 是在class 被装在到ClassLoader之前对其拦截,插入自定义的监听字节码,可实现零侵入的监控,是APM的核心技术

Java1.5之后引入的特性

JavaAgent 运行在 main方法之前 ,内置的方法名为premain,即先执行premain方法,然后再执行main方法。通过premain方法,可实现一个JavaAgent。

javaagent 应用场景:监控、代码覆盖率分析 、JProfiler、应用破解等等等


javaagent的jar包 和 普通jar包的区别

javaagent 其实就是一个jar 包,通过-javaagent:xxx.jar 引入监控目标应用。那这个jar 和普通的jar 的区别在哪里呢?

我们来先看个结论


从零搭建第一个javaagent

maven搭建 编译

【pom.xml】

代码语言:javascript
复制
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>com.artisangroupId>
    <artifactId>javaagentartifactId>
    <version>1.0-SNAPSHOTversion>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-jar-pluginartifactId>
                <version>2.2version>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Project-name>${project.name}Project-name>
                            <Project-version>${project.version}Project-version>
                            <Premain-Class>com.artisan.ssist.JavaAgentDemoPremain-Class>
                            <Boot-Class-Path>javassist-3.18.1-GA.jarBoot-Class-Path>
                            <Can-Redefine-Classes>falseCan-Redefine-Classes>
                        manifestEntries>
                    archive>
                    <skip>trueskip>
                configuration>
            plugin>
        plugins>
    build>
    <dependencies>
        <dependency>
            <groupId>org.javassistgroupId>
            <artifactId>javassistartifactId>
            <version>3.18.1-GAversion>
        dependency>
    dependencies>

project>
  • Premain-Class:指定包含 premain 方法的类名 ,改成自己的类
  • Can-Redefine-Class:是否能重新定义此代理所需的类,默认为 false。

【Agent Code】

代码语言:javascript
复制
package com.artisan.ssist;

import java.lang.instrument.Instrumentation;

public class JavaAgentDemo {

    public  static void premain(String args ,Instrumentation instrumentation){
        System.out.println("premain  first agent demo");
    }
}

【编译成jar】

点击 M, 执行 mvn clean package

查看jar包中的 MANIFEST.MF文件 , MANIFEST.MF文件用于描述Jar包的信息,例如指定入口函数等。


【引入agent jar 为当前应用启动前插入premain逻辑】

jvm参数指定

代码语言:javascript
复制
-javaagent:E:\IdeaProjects\javaagent\target\javaagent-1.0-SNAPSHOT.jar

执行,观察我们引入的这个jar包中的premain方法是否优先于这个测试类的main方法执行

OK ,这个就是Java Agent的 简单小栗子, 更强大的功能继续开篇


javaagent 流程示意图


进阶Demo

代码语言:javascript
复制
public class AgentMain {

    public static void premain(String args, Instrumentation instrumentation)
            throws Exception, ClassNotFoundException {

        // 实例化对象
        UserService userService = new UserService();

        // 类比ClassLoader
        ClassPool classPool = new ClassPool();
        // 追加系统ClassLoader
        classPool.appendSystemPath();
        // 获取一个类
        CtClass ctClass = classPool.get("com.artisan.agent.UserService");
        // 获取方法
        CtMethod sayHello = ctClass.getDeclaredMethod("sayHello");
        // 在方法执行之后插入下面这行语句
        sayHello.insertAfter("System.out.println(\"I am fine\");");
        // 重新定义一个类
        instrumentation.redefineClasses(new ClassDefinition(UserService.class,ctClass.toBytecode()));

        // 调用服务   这里的userservice 已经是被重新定义的 对象了
        userService.sayHello();
    }

总结

  • 1.instrumentation addTransformer 类装载拦截
  • 2.只能拦截未装载过的类
  • 3.instrumentation#retransformClasses方法 重新装载类 ,必须开启相关参数
  • 4.instrumentation.redefineClasses 重新定义一个类 ,不能添加新方法 ,必须开启相关参数

开启参数

代码语言:javascript
复制
agent 依懒包逗号分割
Boot-Class-Path: javassist-3.18.1-GA.jar
是否允许重定义
Can-Redefine-Classes: true
允许重载
Can-Retransform-Classes:true

Javassist 引入

既然是搞字节码,有没有类库 ?

其实上面的栗子 其实已经使用了Javassist 类库了~

Javassist是一个开源的分析、编辑和创建Java字节码的类库。

关于java字节码的处理, 目前有很多开源工具可用,比如asm,bcel, 不过这些都需要直接跟虚拟机指令打交道,实在是太难。。。。。

如果不想了解虚拟机指令,可以采用javassist。

javassist是jboss的一个子项目,优点简单 快速 ,直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/07/16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是javaagent
  • javaagent的jar包 和 普通jar包的区别
  • 从零搭建第一个javaagent
    • 【pom.xml】
    • 【Agent Code】
    • 【编译成jar】
    • 【引入agent jar 为当前应用启动前插入premain逻辑】
  • javaagent 流程示意图
  • 进阶Demo
  • Javassist 引入
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档