JavaAgent

作者: 越狱的灵感 | 来源:发表于2022-06-08 09:44 被阅读0次

前言

java agent即为java.lang.instrument。官方解释

1.png
可以理解为字节码增强技术。一般结合字节码修改框架,比如Javassist,ASM(门槛比较高)等框架一起使用。比如pinpoint,skywalking,arthas等做全链路监控或者服务分析。

技术原理

参考你假笨大佬的图


2.png

写个DEMO

1,首先引入javassist字节码编辑包工具

<dependency>
   <groupId>org.javassist</groupId>
   <artifactId>javassist</artifactId>
</dependency>

2,编写一个待注入服务,并打包成jar包

//--接口
public class JobService {
    public void exec(String params) {
        System.out.println("JobService start job.....");
        System.out.println("job params: " + params + ".");
        System.out.println("JobService end job.....");
    }
}
//--调用接口主函数
public class JavaAgentMainTest {
    public static void main(String[] args) {
        test1();
    }
 
    private static void test1() {
        JobService jobService = new JobService();
        jobService.exec("a=1;b=2;");
    }
}

3,编译打包成jar


3.png

注意第4步需要在 src/main/resources/目录下生成MANIFEST.MF文件,记得在Main-Class后面需要有一个空行。


4.png
打包
5.png

4,检测jar包是否打包正常
java -jar examples.jar


6.png

5,编写javaagent插件jar包
给JobService.exec添加耗时统计的代码

#字节码编辑类
public class TimeConsumerTransformer implements ClassFileTransformer {
 
    final static String startTime = "\nlong startTime = System.nanoTime();\n";
    final static String endTime = "\nlong endTime = System.nanoTime();\n";
 
    final static Map<String, List<String>> methodMap = new HashMap<>();
 
    public TimeConsumerTransformer() {
        //--把代理的类全部加到待处理链表中
        addMethod("com.whg.ex.deeplearnv2.examples.javaagents.JobService", "exec");
    }
 
    private TimeConsumerTransformer addMethod(String className, String methodName) {
        List<String> list = methodMap.computeIfAbsent(className, cn -> new ArrayList<>());
        list.add(methodName);
        return this;
    }
 
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        className = className.replace("/", ".");
        System.out.println("agent className:" + className);
        if (methodMap.containsKey(className)) {
            try {
                CtClass ctClass = ClassPool.getDefault().get(className);
                //--给对应对象的所有方法添加耗时统计
                for (String methodName : methodMap.get(className)) {
                    String cost = "\nSystem.out.println(\"   Method:"
                            + methodName
                            + " Cost:\"+(endTime-startTime)+"
                            + "\"ns\");\n";
                    CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
                    String wrappedMethodName = methodName + "$wrapped";
                    ctMethod.setName(wrappedMethodName);
                    CtMethod newMethod = CtNewMethod.copy(ctMethod, methodName, ctClass, null);
                    StringBuilder newMethodBody = new StringBuilder();
                    newMethodBody.append("{");
                    newMethodBody.append(startTime);
                    newMethodBody.append(wrappedMethodName + "($$);\n");
                    newMethodBody.append(endTime);
                    newMethodBody.append(cost);
                    newMethodBody.append("}");
                    newMethod.setBody(newMethodBody.toString());
                    ctClass.addMethod(newMethod);
                }
                return ctClass.toBytecode();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
 
 
#插件类
public class JavaTcAgentPlugins {
    public static void premain(String agentArgs, Instrumentation instrumentation) {
        System.out.println("JavaAgentTimeConsumer start");
        System.out.println("JavaAgentTimeConsumer params:" + agentArgs);
        instrumentation.addTransformer(new TimeConsumerTransformer());
        System.out.println("JavaAgentTimeConsumer result");
    }
 
    public static void main(String[] args) {
        //--为打包成jar作用
        System.out.println("JavaTimeConsumerAgent test...");
    }
}

6,按之前的方式打包jar


7.png

需要注意的是MANIFEST.MF需要修改为Premain-Class。


8.png

7,测试
执行java -javaagent:../examples_plugins_jar/examples-plugins.jar=whgtest -jar examples.jar


9.png

可以看到耗时统计的代码已经动态添加到原方法中了。

相关文章

  • JavaAgent开发

    JavaAgent开发

  • bytebuddy,Failed to load class "

    我们通过bytebuddy开发javaagent最终要部署到springboot项目中,javaagent引入了s...

  • Caused by: java.lang.VerifyError

    java -jar -javaagent:demo.jar今天我java -jar -javaagent执行一个j...

  • JavaAgent(转载)

    一、简单介绍JavaAgent 是JDK 1.5 以后引入的,也可以叫做Java代理 JavaAgent 是运行在...

  • -javaagent

    Java探针-Java Agent技术 在利用JetbrainsCrack对IDEA进行破解的时候有用到如下-ja...

  • JavaAgent

    前言 java agent即为java.lang.instrument[https://docs.oracle.c...

  • JVM源码分析之javaagent原理完全解读

    注:文章首发于InfoQ:JVM源码分析之javaagent原理完全解读 概述 本文重点讲述javaagent的具...

  • 动手写一个javaagent

    子曰:小胜靠智,大胜靠德,常胜靠身体。 1 什么是javaagent javaagent是一个JVM“插件”,一种...

  • Java Agent基本简介和使用

    javaagent简介 javaagent是一种能够在不影响正常编译的情况下,修改字节码。java作为一种强类型的...

  • JavaAgent技术

    java 提供了操作运行时字节码的机制,见包java.lang.instrument。可以用java开发一个jar...

网友评论

    本文标题:JavaAgent

    本文链接:https://www.haomeiwen.com/subject/moejmrtx.html