我们知道,简单的实现一个java agent是实现如下接口
public static void premain(String agentArgs, Instrumentation inst); //【1】public static void premain(String agentArgs); //【2】
其中,【1】和【2】同时存在时,【1】会优先被执行,而【2】则会被忽略。
这两个都适合在应用启动的时候加载,我们也可以提供一种动态挂载的方式,代码如下
public static void agentmain(String agentArgs, Instrumentation inst){System.out.println("load agent...");inst.addTransformer(new AgentClazzTransformer(),true);}
基于此,我们把agent的基本项目结构搭建起来
<?xml version="1.0" encoding="UTF-8"?><project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>jvm_sandbox_demo</artifactId><groupId>com.deer</groupId><version>1.0-SNAPSHOT</version><relativePath>../pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><groupId>com.deer.agent</groupId><artifactId>jvm_sandbox_agent</artifactId><name>jvm_sandbox_agent</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>2.5.5</version><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><archive><manifestEntries><Premain-Class>com.deer.agent.AgentMain</Premain-Class><Agent-Class>com.deer.agent.AgentMain</Agent-Class><Can-Redefine-Classes>true</Can-Redefine-Classes><Can-Retransform-Classes>true</Can-Retransform-Classes></manifestEntries></archive></configuration><executions><execution><goals><goal>attached</goal></goals><phase>package</phase></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><configuration><skipTests>true</skipTests></configuration></plugin></plugins></build></project>
package com.deer.agent;import com.deer.agent.sandbox.AgentClazzTransformer;import java.lang.instrument.Instrumentation;public class AgentMain {public static void premain(String agentArgs, Instrumentation inst) {System.out.println("premain");}public static void agentmain(String agentArgs, Instrumentation inst){System.out.println("load agent...");inst.addTransformer(new AgentClazzTransformer(),true);}}
package com.deer.agent.sandbox;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.IllegalClassFormatException;import java.security.ProtectionDomain;public class AgentClazzTransformer implements ClassFileTransformer {@Overridepublic byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {if(className!=null && className.startsWith("com/deer/base/service")){System.out.println("I can see you ...."+className);}return classfileBuffer;}}
基于此,我们把要测试的代码稍微修改一下
package com.deer.base.controller;import com.deer.base.service.BaseService;import com.deer.base.service.HelloService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class HelloController {@Autowiredprivate HelloService helloService;@RequestMapping("/sayHi/{userName}")public String sayHello(@PathVariable(name ="userName") String userName) {//新增加的代码BaseService.record(userName);return helloService.sayHello(userName);}}
package com.deer.base.service;public class BaseService {public static void record(String value){System.out.println("one record:"+value);}}
