1、建立一個maven專案,不要用springboot的
引入依賴
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.29.0-GA</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.3.24</version> </dependency>
其中 javassist這個依賴必須的 其他是程式碼邏輯用到的 根據自己需要來
設定打包外掛
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <configuration> <!--將所有依賴都打入同一個jar包中--> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <!--指定java agent相關配置檔案--> <archive> <manifestFile>src/main/resources/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin>
編寫主類程式碼
JavaAgent.java
import java.lang.instrument.Instrumentation; /** * 攔截列印方法的返回值 */ public class JavaAgent { public static void premain(String agentArgs, Instrumentation inst) { inst.addTransformer(new ClassPreProcessorAgentAdapter(), true); } }
agentArgs:可以透過這個把一些引數傳進來
ClassPreProcessorAgentAdapter.java
import javassist.*; import org.apache.commons.lang3.StringUtils; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; /** * 列印方法返回值 具體邏輯 */ public class ClassPreProcessorAgentAdapter implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { //是我們自己寫的類才列印 if (StringUtils.isBlank(className)) { return classfileBuffer; } //將類名路徑 / 換成 . String classPkgName = className.replace('/', '.'); //如果不是我們寫的類 直接返回 這裡自定義邏輯 if (!classPkgName.contains("IndexController")) { return classfileBuffer; } final ClassPool pool = ClassPool.getDefault(); try { CtClass ctClass = pool.makeClass(new java.io.ByteArrayInputStream(classfileBuffer)); //匹配類的路徑是我們要的才列印 if (ctClass.getName().replace('/', '.').startsWith("com.example.demotest")) { for (CtMethod method : ctClass.getDeclaredMethods()) { if (method.hasAnnotation(org.springframework.web.bind.annotation.GetMapping.class)) { // 這句話最重要 列印返回值的內容 method.insertAfter("System.out.println(\"Controller Method Returned: \" + $_);"); } } return ctClass.toBytecode(); } } catch (Exception e) { e.printStackTrace(); } System.out.println("premain load Class:" + className); return classfileBuffer; } }
以上只是虛擬碼 而且只有請求上有@GetMappting的註解才會列印
然後resource下放檔案
MANIFEST.MF
Manifest-Version: 1.0 Specification-Title: Log Agent Specification-Version: 0.0.1 Specification-Vendor: LogAgent Implementation-Title: log.agent Implementation-Version: 0.0.1 Implementation-Vendor: LogAgent Premain-Class: com.demo.agent.JavaAgent Can-Redefine-Classes: true Can-Retransform-Classes: true
Premain-Class:這個就是我們寫的premain的類的全路徑 我這裡是JavaAgent的類路徑 根據自己的來
最後一行要空一行 ,這個不能少
最後打包,會生成一個 jar-with-dependencies.jar結尾的jar包,然後我們透過啟動的時候命令引用進去即可
-javaagent:D:\jar包路徑\agent-jar-with-dependencies.jar
IDEA的話是在那個啟動類的 VM options裡面設定
如果要除錯程式碼的話 要把啟動的專案和我們agent的專案放在一個工程底下,這樣idea就能自動斷點到