一.JavaAgent概述

1.JavaAgent简述

        使用Skywalking的时候,并没有修改程序中任何一行 Java 代码,这里便使用到了Java Agent 技术。

        我们平时用过的很多工具都是基于java Agent来实现的,例如:

        <1> 热部署工具JRebel

         <2> springboot的热部署插件

        <3>  各种线上诊断工具(btrace, greys)

        <4>  阿里开源的arthas等等

 2.Agent分为两种

        (1)在主程序之前运行的Agent

        (2)在主程序之后运行的Agent

二..JavaAgent入门

1.premain(主程序之前运行的Agent)

(1)说明

        在实际使用过程中,javaagent是java命令的一个参数。通过java 命令启动我们的应用程序的时候,可通过参数 -javaagent 指定一个 jar 包(也就是我们的代理agent),能够实现在我们应用程序的主程序运行之前来执行我们指定jar 包中的特定方法,在该方法中我们能够实现动态增强Class等相关功能,并且该 jar包有2个要求:

        <1> 这个 jar 包的 META-INF/MANIFEST.MF 文件必须指定 Premain-Class 项,该选项指定的是一个类的全路径.

        <2> Premain-Class 指定的那个类必须实现 premain() 方法。

        META-INF/MANIFEST.MF文件内容如下

Manifest-Version: 1.0
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: com.itheima.PreMainAgent

注意:

        <1> 最后需要多一行空行

        <2> Can-Redefine-Classes :true表示能重定义此代理所需的类, 默认值为 false(可选)

        <3> Can-Retransform-Classes :true 表示能重转换此代理所需的 类,默认值为 false (可选)

        <4> Premain-Class :包含 premain 方法的类(类的全路径名)

(2)premain案例demo

<1> 创建java-agent工程,pom.xml配置如下

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>

    <groupId>com.itheima</groupId>
    <artifactId>agent-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <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>


    <build>
        <plugins>
            <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.itheima.agent.PreMainAgent</Premain-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>
        </plugins>
    </build>

</project>

<2>编写一个java agent程序

public class PreMainAgent {
    public static void premain(String agentArgs,Instrumentation inst) {
        System.out.println("我的agent程序跑起来啦!");
        System.out.println("收到的agent参数是:"+agentArgs);
    }
}

<3>对java-agent工程打包得到 java-agent-1.0-SNAPSHOT.jar

<4>创建 agent-test 项目,编写一个类: com.itheima.Application

public class Application {
    public static void main(String[] args) {
        System.out.println("main 函数 运行了 ");
    }
}

<5>启动运行,添加 -javaagent 参数

-javaagent:D:\develop\javaagent\agent-demo-1.0-SNAPSHOT.jar=option1=value1,option2=value2

java 探针开发 java探针监控_java 探针开发

<6>运行结果

我的agent程序跑起来啦!
收到的agent参数是:k1=v1,k2=v2
main 函数 运行了

<7>总结

这种agent JVM 会先执行 premain 方法,大部分类加载都会通过该方法,
注意:是大部分,不是所有。当然,遗漏的主要是系统类,因为很多系统类
先于 agent 执行,而用户类的加载肯定是会被拦截的。也就是说,这个方法
是在 main 方法启动前拦截大部分类的加载活动,既然可以拦截类的加载,
那么就可以去做重写类这样的操作,结合第三方的字节码编译工具,比如ASM,
bytebuddy,javassist,cglib等等来改写实现类。