编程语言-Java系列一些收藏

JAVA进阶篇(7)—Java agent从0到1的踩坑过程

2020-08-17  本文已影响0人  小胖学编程

1. java agent技术简介

在JDK1.5之后,可以使用agent技术构建一个独立于应用程序的代理程序(即Agent)。可以用来协助监测、运行甚至替换其他JVM上的程序。使用它可以实现虚拟机级别的AOP功能。

2. Agent案例

2.1 最简单的Agent案例

2.1.1 代码

基础的demo可以参考:
一个最简单的javaagent demo实例

2.1.2 打包方式

注意:这种打包方式和maven的打包方式是不同的,maven的打包方式可见下文。

在此处进入
生成Build Artifact是在Build->Build Artifact下生成的。
在这里插入图片描述

2.1.3 生成jar包时,需要注意编译的JDK版本。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 复杂的Agent案例

目的:AOP装饰线程池的Runnable、Callable类。
项目对应的GitHub地址

2.2.1 配置启动项

启动项的地址为生成jar的绝对地址:

-javaagent:/Users/yexuerui/Documents/veradm/agenttest/out/artifacts/agenttest_jar/agenttest.jar
配置启动项

2.2.2 生成jar包

1. agent项目的文件出现NoClassDefFoundError异常:

使用agent的AOP代理JDK的源码后,agent的jar包需要启动类加载器上。即需要配置MF文件:Boot-Class-Path: agenttest.jar

因为修改的是JDK的标准库的类,而标准库的类是由bootstrap class loader类加载器加载的,而上面修改的ThreadPoolExecutor类引用了agent类的代码,所以agent的jar包需要加到boot class path上。即需要去配置MF文件中的Boot-Class-Path

如果不修改,会出现:


在这里插入图片描述

2. agent项目依赖的jar出现NoClassDefFoundError异常:

问题:agent项目依赖了A包,但是实际使用agent代理的项目里面也依赖了A包。此时,使用-javaagent: agent.jar时,却是出现了NoClassDefFoundError异常。

解决方案一:所以当使用idea进行打包时,需要如下配置MF文件:在Boot-Class-Path配置依赖的jar

Manifest-Version: 1.0
Class-Path: spotbugs-annotations-4.1.1.jar jsr305-3.0.2.jar javassist-
 3.23.2-GA.jar
Premain-Class: com.yyy.agent.demo.agent.TtlAgent
Can-Redefine-Classes: true
Can-Set-Native-Method-Prefix: true
Boot-Class-Path: agenttest.jar javassist-3.23.2-GA.jar
Can-Retransform-Classes: true

(推荐)解决方案二:javassist-3.23.2-GA.jar打入到agenttest.jar中,可以使用下面的maven打包的方式。

(1) 配置MF文件,打包的时候,自动生成MF文件配置:maven-jar-plugin插件
(2) 将javassist的jar包内容打入到生成的jar包中

<build> 
  <!-- 生成MF的插件-->  
  <plugins> 
    <plugin> 
      <artifactId>maven-jar-plugin</artifactId>  
      <version>2.4</version>  
      <configuration> 
        <archive> 
          <manifestEntries> 
            <Premain-Class>com.yyy.agent.demo.agent.TtlAgent</Premain-Class>  
            <Boot-Class-Path>${project.artifactId}-${project.version}.jar</Boot-Class-Path>  
            <Can-Redefine-Classes>true</Can-Redefine-Classes>  
            <Can-Retransform-Classes>true</Can-Retransform-Classes>  
            <Can-Set-Native-Method-Prefix>false</Can-Set-Native-Method-Prefix> 
          </manifestEntries> 
        </archive> 
      </configuration> 
    </plugin>  
    <!-- 将依赖jar打入项目的插件-->  
    <plugin> 
      <artifactId>maven-shade-plugin</artifactId>  
      <version>3.2.4</version>  
      <executions> 
        <execution> 
          <id>shade-when-package</id>  
          <phase>package</phase>  
          <goals> 
            <goal>shade</goal> 
          </goals>  
          <configuration> 
            <relocations> 
              <relocation> 
                <pattern>javassist</pattern>  
                <shadedPattern>com.yyy.agent.demo.agent.internal.javassist</shadedPattern> 
              </relocation> 
            </relocations>  
            <artifactSet> 
              <includes> 
                <include>org.javassist:javassist</include> 
              </includes> 
            </artifactSet>  
            <shadeSourcesContent>true</shadeSourcesContent> 
          </configuration> 
        </execution> 
      </executions> 
    </plugin> 
  </plugins> 
</build>

3. 多个依赖的jar包打入到项目

<plugin> 
  <artifactId>maven-shade-plugin</artifactId>  
  <version>3.2.4</version>  
  <executions> 
    <execution> 
      <id>shade-when-package</id>  
      <phase>package</phase>  
      <goals> 
        <goal>shade</goal> 
      </goals>  
      <configuration> 
        <relocations> 
          <!--若是jar1不修改目录名,无需relocations配置-->  
          <relocation> 
            <!-- 需要修改的目录名-->  
            <pattern>javassist</pattern>  
            <!--修改后的目录名 -->  
            <shadedPattern>com.yyy.agent.demo.agent.internal.javassist</shadedPattern> 
          </relocation> 
        </relocations>  
        <artifactSet> 
          <includes> 
            <!-- 需要打入的jar1-->  
            <include>org.apache.skywalking:apm-toolkit-trace</include>  
            <!-- 需要打入的jar2-->  
            <include>org.javassist:javassist</include> 
          </includes> 
        </artifactSet>  
        <shadeSourcesContent>true</shadeSourcesContent> 
      </configuration> 
    </execution> 
  </executions> 
</plugin>

pattern:配置的是:

image.png

shadedPattern:配置的修改后的名字。

include配置的是:

image.png

4. 生成jar包的超时

 mvn clean install

遇到的问题:


在这里插入图片描述

生成jar包的时候,可能会出现这个问题,看上去是网络超时。原因是:连接的公司内网,所以不能进行下载。解决方案就是使用手机热点进行下载。

最终生成agent.jar的格式:

在这里插入图片描述

项目对应的GitHub地址

3. 推荐阅读

调用链上下文跨线程传递

☆基于Java Instrument的Agent实现

maven-shade-plugin介绍及使用

  1. 将依赖的jar包打包到当前jar包(常规打包是不会将所依赖jar包打进来的);
  2. 对依赖的jar包进行重命名(用于类的隔离);
上一篇下一篇

猜你喜欢

热点阅读