一、javaagent可以做什么?
此时你还坚定的认为Java程序最先执行的是main方法?今天教你如何打破平凡!造就不平凡的你!javaagent帮你做到,当你的主程序运行之前或者运行时都可以运行部分你的其他逻辑!
1、创建java maven项目
2、在resources下创建META-INF/MANIFEST.MF文件,内容为:
Manifest-Version: 1.0
Created-By: hi.zhaojinwei.work
Premain-Class: com.zjw.PremainClass
Agent-Class: com.zjw.AgentClass
3、maven pom文件依赖打包插件maven-jar-plugin
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Premain-Class>
com.zjw.PremainClass
</Premain-Class>
<Agent-Class>
com.zjw.AgentClass
</Agent-Class>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
4、创建com.zjw.PremainClass和com.zjw.AgentClass类
package com.zjw;
import java.lang.instrument.Instrumentation;
public class PremainClass {
private static Instrumentation instrumentation;
public static void premain(String args, Instrumentation instrumentation) {
PremainClass.instrumentation = instrumentation;
}
public static long getObjectSize(Object o) {
return instrumentation.getObjectSize(o);
}
}
package com.zjw;
import java.lang.instrument.Instrumentation;
public class AgentClass {
public static void agentmain(String args, Instrumentation instrumentation) {
System.out.println("agentmain args:" + args);
Class[] initiatedClasses = instrumentation.getAllLoadedClasses();
for (Class initiatedClass : initiatedClasses) {
System.out.println(initiatedClass);
}
}
}
5、在主程序项目中依赖javaagent项目jar,并且jvm参数设置为javaagent jar包的路径:
-javaagent:/Users/zhaojinwei/Desktop/javaagent/target/javaagent-1.0.jar
6、启动主程序就可以正常调用javaagent的获取对象大小内存大小的方法了
Object o=new Object();
long objectSize = PremainClass.getObjectSize(o);
System.out.println(objectSize);
7、AgentClass 怎么执行呢?当主程序运行时新启动一个java项目调用:
public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
//获取本机中所有的jvm描述对象
List<VirtualMachineDescriptor> list = VirtualMachine.list();
AtomicReference<String> id=new AtomicReference<>();
list.forEach(p->{
if("com.example.demo.DemoApplication".equals(p.displayName())){
//com.example.demo.DemoApplication为主程序的displayName,即:这里获取主程序jvm的进程id
id.set(p.id());
}
});
//将主进程id传入attach
VirtualMachine vm = VirtualMachine.attach(id.get());
//javaagent jar的位置和AgentClass.agentmain的参数
vm.loadAgent("/Users/zhaojinwei/Desktop/javaagent/target/javaagent-1.0.jar","zhaojinwei1");
}
8、运行这个新项目,会看见你的主程序执行了AgentClass.agentmain方法
注意:你的主程序一直处于运行状态AgentClass.agentmain才能正常调用,不然主程序运行结束新的项目就不能通过VirtualMachine.attach(id.get())连接不到你的主程序jvm进程,比如我们主程序可以是一个spring boot web项目