Skyworking原理Javaagent

Instrumentation:

classFileTransformer: 提供自定义字节码转换方法,transfer方法在类被加载 重定义的时候被调用

  1. JavaAgent
  • 获取所有已经加载过的类
  • 获取所有已经初始化的类(执行过clinit)
  • 获取某个对象大小
  • 将某个jar加入到bootstrap classpath作为高优先级被bootstrapClassLoader加载
  • 将某个jar加入到classpath里供AppClasloard加载
  • 设置某些native方法前缀,在查找native方法的时候做规则匹配
  1. 使用
  • 自己写的agent打包成jar
  • 启动命令 java -javaagent:D:\tool_software\myagent.jar=param=someparam -jar 项目jar
  • javaagent 指定装备jar路径
  1. java.lang.instrument 装配API
  1. Instrumentation
  • 提供装备Java代码的服务方法(修改字节码机制),启动Agent时会传入premain或者agentmain方法

      premain 和 agentmain区别:
      用命令行 -javaagent 在程序启动前处理的 premain
                          在程序启动后处理的 agentmain
    
  1. ClassFileTransformer
  • 需要一个它的实现类,以进行自定义字节码转换
  1. Javaassist
  • 处理Java字节码类库
  • 允许运行时定义类
  • 加载类时修改类
  • 提供两种级别API 源码级别、字节码级别
  • 源代码级别支持编写java源码一样修改类文件,javaassist会即时编译
  • 读取和写入字节码
 Javassist.CtClass 是类文件的抽象表示形式
 
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("test.Rectangle");
cc.setSuperclass(pool.get("test.Point"));
cc.writeFile();

byte[] b = cc.toBytecode();
Class clazz = cc.toClass();
  • 定义类
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("Point");

CtNewMethod
addMethod

makeInterface
abstractMethod
  • 创建类
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("com.du.Hello");
CtMethod ctMethod = CtMethod.make("public void sayHello(){System.out.println(\"Hello Javaassist\");}",ctClass);
ctClass.addMethod(ctMethod);
Class c = ctClass.toClass();
ctClass.detach();
Object o = c.newInstance();
Method method = c.getMethod("sayHello");
method.invoke(o);

输出:
Hello Javaassist
  • 修改类
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.getCtClass("com.du.cdty.TestClass");
CtMethod ctMethod = ctClass.getDeclaredMethod("compute");
ctMethod.insertAfter("System.out.println(\"compute after param \"+java.util.Arrays.toString($args)+\",return \"+ $_);");
ctClass.toClass();
ctClass.detach();

TestClass testClass = new TestClass();
testClass.compute(10);


class TestClass{
    public int compute(int param) {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return param + 1000;
    }
}

输出:
compute after param [10],return 1010
  • 拦截方法
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setSuperclass(TestClass.class);
        proxyFactory.setFilter(new MethodFilter() {
            public boolean isHandled(Method method) {
                if ("compute".equals(method.getName()))
                    return true;
                return false;
            }
        });
        Class aClass = proxyFactory.createClass();
        TestClass testClass = (TestClass) aClass.newInstance();
        ((Proxy)testClass).setHandler(new MethodHandler() {
            public Object invoke(Object o, Method method, Method method1, Object[] objects) throws Throwable {
                long start = System.currentTimeMillis();
                try {
                    return method1.invoke(o,objects);
                } catch (Exception e){
                    throw e;
                } finally {
                    long end = System.currentTimeMillis() - start;
                    System.out.println("call mathod name: "+method.getName()
                    +" cat time "+ end);
                }
            }
        });

        System.out.println(testClass.compute(11));

输出:
call mathod name: compute cat time 3000
1011

你可能感兴趣的:(链路追踪)