我们知道,简单的实现一个java agent是实现如下接口

    1. public static void premain(String agentArgs, Instrumentation inst); //【1】
    2. public static void premain(String agentArgs); //【2】

    其中,【1】和【2】同时存在时,【1】会优先被执行,而【2】则会被忽略。
    这两个都适合在应用启动的时候加载,我们也可以提供一种动态挂载的方式,代码如下

    1. public static void agentmain(String agentArgs, Instrumentation inst){
    2. System.out.println("load agent...");
    3. inst.addTransformer(new AgentClazzTransformer(),true);
    4. }

    基于此,我们把agent的基本项目结构搭建起来

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <parent>
    5. <artifactId>jvm_sandbox_demo</artifactId>
    6. <groupId>com.deer</groupId>
    7. <version>1.0-SNAPSHOT</version>
    8. <relativePath>../pom.xml</relativePath>
    9. </parent>
    10. <modelVersion>4.0.0</modelVersion>
    11. <groupId>com.deer.agent</groupId>
    12. <artifactId>jvm_sandbox_agent</artifactId>
    13. <name>jvm_sandbox_agent</name>
    14. <properties>
    15. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    16. <maven.compiler.source>1.8</maven.compiler.source>
    17. <maven.compiler.target>1.8</maven.compiler.target>
    18. </properties>
    19. <build>
    20. <plugins>
    21. <plugin>
    22. <groupId>org.apache.maven.plugins</groupId>
    23. <artifactId>maven-assembly-plugin</artifactId>
    24. <version>2.5.5</version>
    25. <configuration>
    26. <descriptorRefs>
    27. <descriptorRef>jar-with-dependencies</descriptorRef>
    28. </descriptorRefs>
    29. <archive>
    30. <manifestEntries>
    31. <Premain-Class>com.deer.agent.AgentMain</Premain-Class>
    32. <Agent-Class>com.deer.agent.AgentMain</Agent-Class>
    33. <Can-Redefine-Classes>true</Can-Redefine-Classes>
    34. <Can-Retransform-Classes>true</Can-Retransform-Classes>
    35. </manifestEntries>
    36. </archive>
    37. </configuration>
    38. <executions>
    39. <execution>
    40. <goals>
    41. <goal>attached</goal>
    42. </goals>
    43. <phase>package</phase>
    44. </execution>
    45. </executions>
    46. </plugin>
    47. <plugin>
    48. <groupId>org.apache.maven.plugins</groupId>
    49. <artifactId>maven-surefire-plugin</artifactId>
    50. <configuration>
    51. <skipTests>true</skipTests>
    52. </configuration>
    53. </plugin>
    54. </plugins>
    55. </build>
    56. </project>
    1. package com.deer.agent;
    2. import com.deer.agent.sandbox.AgentClazzTransformer;
    3. import java.lang.instrument.Instrumentation;
    4. public class AgentMain {
    5. public static void premain(String agentArgs, Instrumentation inst) {
    6. System.out.println("premain");
    7. }
    8. public static void agentmain(String agentArgs, Instrumentation inst){
    9. System.out.println("load agent...");
    10. inst.addTransformer(new AgentClazzTransformer(),true);
    11. }
    12. }
    1. package com.deer.agent.sandbox;
    2. import java.lang.instrument.ClassFileTransformer;
    3. import java.lang.instrument.IllegalClassFormatException;
    4. import java.security.ProtectionDomain;
    5. public class AgentClazzTransformer implements ClassFileTransformer {
    6. @Override
    7. public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
    8. if(className!=null && className.startsWith("com/deer/base/service")){
    9. System.out.println("I can see you ...."+className);
    10. }
    11. return classfileBuffer;
    12. }
    13. }

    基于此,我们把要测试的代码稍微修改一下

    1. package com.deer.base.controller;
    2. import com.deer.base.service.BaseService;
    3. import com.deer.base.service.HelloService;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.web.bind.annotation.PathVariable;
    6. import org.springframework.web.bind.annotation.RequestMapping;
    7. import org.springframework.web.bind.annotation.RestController;
    8. @RestController
    9. public class HelloController {
    10. @Autowired
    11. private HelloService helloService;
    12. @RequestMapping("/sayHi/{userName}")
    13. public String sayHello(@PathVariable(name ="userName") String userName) {
    14. //新增加的代码
    15. BaseService.record(userName);
    16. return helloService.sayHello(userName);
    17. }
    18. }
    1. package com.deer.base.service;
    2. public class BaseService {
    3. public static void record(String value){
    4. System.out.println("one record:"+value);
    5. }
    6. }