使用javaagent参数保存二进制class文件
使用-javaagent 参数用户可以在执行main函数前执行一些其他操作,如可以动态的修改替换类中代码。既然可以修改类那么自然就可以获取到类(class二进制)了。 本文同样使用maven去打一个包
1、编写pom.xml,此处仅仅是定义一个jar工程
<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.hode</groupId>
<artifactId>clazzagent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive><!-- 如果没有被正确打进jar包,请确认MANIFEST.MF是否正确,直接拷贝正确的自动生成的 -->
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
2、编写一个导出class的类,此类实现了ClassFileTransformer接口并且实现了一个静态方法premain,为了简单起见,只保存指定包下的类二进制文件到指定的目录中。 代码如下 ClazzGenerateAgent .java
package com.hode;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
/**
* 导出生成类ClazzGenerateAgent
* 需要实现一个静态的public static void premain(String agentArgs,Instrumentation inst)方法
*/
public class ClazzGenerateAgent implements ClassFileTransformer{
public static void premain(String agentArgs,Instrumentation inst){
inst.addTransformer(new ClazzGenerateAgent());
}
@Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
//只导出指定包名下的类
if(className.contains("com/hode")){
System.out.println(className);
int lastIndexOf = className.lastIndexOf("/") + 1;
String fileName = className.substring(lastIndexOf) + ".class";
exportClazz("c:/clazz/", fileName, classfileBuffer);
System.out.println(className+" export success!");
}else{
}
return null;
}
/**
* 将data保存到文件中
* @param path
* @param filename
* @param data
*/
private void exportClazz(String path,String filename,byte[] data){
try{
File file = new File(path+filename);
if(!file.exists()){
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(data);
bos.close();
fos.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
3、接着自定义编写一个MANIFEST.MF文件,文件目录src/main/resources/META-INF/MANIFEST.MF,内容如下
MANIFEST.MF
Manifest-Version: 1.0
Premain-Class: com.hode.ClazzGenerateAgent
Archiver-Version: Plexus Archiver
Built-By: hode
Created-By: Apache Maven 3.3.3
Build-Jdk: 1.8.0_66
4、执行命令,完成安装
mvn clean install
安装完成后,可以在maven仓库目录查看jar包,如目录在d:\repository\com\hode\clazzagent\0.0.1-SNAPSHOT\clazzagent-0.0.1-SNAPSHOT.jar
5、编写一个测试类并运行
注意:运行时需加上jvm参数-javaagent:"D:\repository\com\hode\clazzagent\0.0.1-SNAPSHOT\clazzagent-0.0.1-SNAPSHOT.jar"package com.hode;
public class Test {
public static void main(String[] args) {
System.out.println("success");
}
}
在eclipse中在VM arguments中填写,在命令行模式下执行,则如下
java -javaagent:"D:\repository\com\hode\clazzagent\0.0.1-SNAPSHOT\clazzagent-0.0.1-SNAPSHOT.jar" com.hode.Test
执行完成后,即可以类ClazzGenerateAgent定义的保存目录c:\clazz中查看到Test.class类文件,使用反编译工具可查看具体内容。
Demo代码下载
结束。