赞
踩
使用Skywalking的时候,并没有修改程序中任何一行 Java 代码,这里便使用到了Java Agent 技术。
我们平时用过的很多工具都是基于java Agent来实现的,例如:
<1> 热部署工具JRebel
<2> springboot的热部署插件
<3> 各种线上诊断工具(btrace, greys)
<4> 阿里开源的arthas等等
(1)在主程序之前运行的Agent
(2)在主程序之后运行的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
<6>运行结果
- 我的agent程序跑起来啦!
- 收到的agent参数是:k1=v1,k2=v2
- main 函数 运行了
<7>总结
- 这种agent JVM 会先执行 premain 方法,大部分类加载都会通过该方法,
- 注意:是大部分,不是所有。当然,遗漏的主要是系统类,因为很多系统类
- 先于 agent 执行,而用户类的加载肯定是会被拦截的。也就是说,这个方法
- 是在 main 方法启动前拦截大部分类的加载活动,既然可以拦截类的加载,
- 那么就可以去做重写类这样的操作,结合第三方的字节码编译工具,比如ASM,
- bytebuddy,javassist,cglib等等来改写实现类。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。