美文网首页编程语言-Java系列一些收藏
JAVA进阶篇(7)—Java agent从0到1的踩坑过程

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

作者: 小胖学编程 | 来源:发表于2020-08-17 17:40 被阅读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包进行重命名(用于类的隔离);

    相关文章

      网友评论

        本文标题:JAVA进阶篇(7)—Java agent从0到1的踩坑过程

        本文链接:https://www.haomeiwen.com/subject/anwqjktx.html