但有时应用在运行中,需要给方法加日志的输出,这时需要对运行中的类进行类的重新加载。
那通过-javaagent命令是无法实现的,只能通过Attach Tools的API来重新加载类。
agent项目改造
premain方法改为agentmain方法
调用retransformClasses来重加载类
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.util.Arrays;
public class Javaagent {
public static void agentmain(String arg, Instrumentation instrumentation) throws UnmodifiableClassException {
System.out.println("agentmain...");
CusClassFileTransformer transformer = new CusClassFileTransformer();
instrumentation.addTransformer(transformer, true);
Class<?>[] allLoadedClasses = Arrays.stream(instrumentation.getAllLoadedClasses())
.filter(item -> !item.getName().startsWith("java"))
.filter(item -> !item.getName().startsWith("sun"))
.filter(item -> !item.getName().startsWith("[L"))
.toArray(Class[]::new);
System.out.println("allLoadedClasses:" + allLoadedClasses.length);
for (Class<?> aClass : allLoadedClasses) {
if ("UserService".equals(aClass.getName())) {
System.out.println("retransformClasses : " + aClass.getName());
instrumentation.retransformClasses(aClass);
instrumentation.removeTransformer(transformer);
pom.xml修改
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifestEntries>
<Agent-Class>Javaagent</Agent-Class>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
改造一下App
使用while循环来调用方法
打印输出结果,观察控制台输出
import java.util.concurrent.atomic.AtomicInteger;
public class App {
public static void main(String[] args) throws InterruptedException {
UserService userService = new UserService();
AtomicInteger count = new AtomicInteger(0);
Thread thread = new Thread(() -> {
while (true) {
System.out.println(count.incrementAndGet() + ":" + userService.queryUserByName("MinXie"));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
thread.start();
thread.join();
System.out.println("end");
使用Attach工具
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import java.io.IOException;
public class Attach {
public static void main(String[] args) throws IOException, AttachNotSupportedException {
attachPid("39984", "/Users/user/IdeaProjects/javaagent/target/javaagent-1.0-SNAPSHOT-jar-with-dependencies.jar");
private static void attachPid(String pid, String jarPath) throws IOException, AttachNotSupportedException {
VirtualMachine vm = VirtualMachine.attach(pid);
System.out.println("attach:" + vm.id());
try {
vm.loadAgent(jarPath, null);
} catch (AgentLoadException | AgentInitializationException e) {
e.printStackTrace();
} finally {
vm.detach();
调用loadAgent来触发agent
这里的pid可以通过jps来输出
启动App,再启动Attach
看控制台输出,看到第八次调用方法之后是有打印方法调用日志的
成功对运行中的类进行字节码插桩
- 826
-
ShadowYD
Istio
Kubernetes