手把手教你Java字节码Demo
接触中间件的开发来说,了解像Pinpoint(https://github.com/naver/pinpoint)、BTrace(https://github.com/btraceio/btrace)、阿里的JVM-SANDBOX(https://github.com/alibaba/jvm-sandbox)、Java在线问题诊断工具Greys(https://github.com/oldmanpushcart/greys-anatomy)等,都是通过字节码技术,无侵入的干预到Java应用程序。很清爽又很实用。
今天就记录字节码的两种实现demo,作为入门了解。
Java Agent的最常用方式:
- 一种是premain方式:它属于静态注入。即在Java应用程序启动时,在类加载器对类的字节码进行加载之前对类字节码进行“再改造”来做功能增强(例如实现AOP)
- 一种是:HotSpot独有的attach方式(JDK1.6才出现),它能实现动态注入,对已经运行的Java应用的类进行字节码增强。
方式一:premain静态方式
(大多中间件/工具的方式)
java -javaagent:/root/application-premain.jar MyApp
如上面这句java启动命令,假定/root目录下已经有一个符合Java Agent规范的Jar了(这里指application-premain.jar),而MyApp是指我们Java应用的启动类(main方法的类),如此我们就能成功的对这个Java应用进行了静态注入。
接下来,分解一下具体实现步骤。
1、建个独立Maven工程
pom的必要依赖和设置
<dependencies>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.21.0-GA</version>
</dependency>
<!-- 注意:如果需要进行attach,那么需要引入tools.jar-->
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
<build>
<finalName>application-premain</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<archive>
<!--避免MANIFEST.MF被覆盖-->
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
<descriptorRefs>
<!--打包时加入依赖-->
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>