0
点赞
收藏
分享

微信扫一扫

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

1. java agent技术简介

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

2. Agent案例

2.1 最简单的Agent案例

2.1.1 代码

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

2.1.2 打包方式


生成Build Artifact是在Build->Build Artifact下生成的。

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



2.2 复杂的Agent案例

2.2.1 配置启动项

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

-javaagent:/Users/yexuerui/Documents/veradm/agenttest/out/artifacts/agenttest_jar/agenttest.jar

2.2.2 生成jar包

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

如果不修改,会出现:


问题: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>
<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:配置的是:

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

include配置的是:

 mvn clean install

遇到的问题:


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

3. 推荐阅读

调用链上下文跨线程传递

☆基于Java Instrument的Agent实现

maven-shade-plugin介绍及使用

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

相关推荐

0 条评论