JAVA-Agent探针打印方法执行的返回值

 

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就能自动断点到

 

posted @ 2024-05-02 22:10  yvioo  阅读(80)  评论(0编辑  收藏  举报