zoukankan      html  css  js  c++  java
  • Java性能监控之javassist探索

    由于个人工作原因,近期遇到多起因应用性能导致业务中断的事情。多次排查分析总结,发现是应用性能问题,当然性能的提现是多维度的,在这里就不赘述了。

    主要关注在应用运行中断之前就发现它(事前处理),是很重要的。

    要监控应用的性能,首先列出性能监控点,然后输出要关注的信息,最终根据信息进行数据分析得出性能瓶颈后进行持续优化改进,在问题爆发前将其扼杀在“子宫”里。

    不同应用、不同场景下,监控点不尽相同,要关注的信息如何获取却是每个工程师都要思考的问题。

    在接触javassist之前,有过几个方案,但发布了几版后发现实现方式太low、成本高、效率低等不足,其中包括:代码中嵌入日志、使用spring管理应用并使用aop、修改jar包源代码增加日志。

    如果是一个新搭建的工程,以上方案可以在框架搭建过程中便包含进去,作为框架的基础能力随同应用一起发布。但是平台上应用很多,明显不是很适用,并且有些操作所带来的风险需要更多的工作量去规避。

    于是,找到了她------javassist。

    javassist的使用要借助于javaagent技术,接下来介绍如何使用javassist

    1、获取javassit-3.20.0-GA.jar

    2、创建类AgentTransformer并实现ClassFileTransformer接口,使用javassist API完成对源类字节码级别的修改

    3、创建类AgentDemo,并增加premain实现public static void premain(String args, Instrumentation inst){ inst.addTransformer(new AgentTransformer()); }

    4、创建MAINFEST.MF文件,内容如下:

    Manifest-Version: 1.0
    Premain-Class: AgentDemo
    Can-Redefine-Classes: true
    Can-Retransform-Classes: true

    5、打jar包:main class指定使用MAINFEST.MF文件

     

    6、实际应用--创建demo应用,引入两个jar包:javassist-3.20.0-GA.jar和javassistdemo.jar(上面打包出来的)

    7、修改java启动参数

    8、运行应用程序,观察结果

    System.out.println("This code is inserted before constructor sun/misc/URLClassPath$FileLoader$1");
    System.out.println("This code is inserted after constructor sun/misc/URLClassPath$FileLoader$1");
    This code is inserted before constructor sun/misc/URLClassPath$FileLoader$1
    This code is inserted after constructor sun/misc/URLClassPath$FileLoader$1
    System.out.println("This code is inserted before constructor com/hope/javassistapp/app/App");
    System.out.println("This code is inserted after constructor com/hope/javassistapp/app/App");
    System.out.println("This code is inserted before constructor sun/misc/Cleaner");
    System.out.println("This code is inserted after constructor sun/misc/Cleaner");
    System.out.println("This code is inserted before constructor java/lang/Enum");
    System.out.println("This code is inserted after constructor java/lang/Enum");
    This code is inserted before constructor sun/misc/URLClassPath$FileLoader$1
    This code is inserted after constructor sun/misc/URLClassPath$FileLoader$1
    System.out.println("This code is inserted before constructor com/hope/javassistapp/construct/JavassistDemo1");
    System.out.println("This code is inserted after constructor com/hope/javassistapp/construct/JavassistDemo1");
    This code is inserted before constructor com/hope/javassistapp/construct/JavassistDemo1
    JavassistDemo1:自身构造函数输出内容
    This code is inserted after constructor com/hope/javassistapp/construct/JavassistDemo1
    This code is inserted before constructor sun/misc/URLClassPath$FileLoader$1
    This code is inserted after constructor sun/misc/URLClassPath$FileLoader$1
    System.out.println("This code is inserted before constructor com/hope/javassistapp/construct/JavassistDemo2");
    System.out.println("This code is inserted after constructor com/hope/javassistapp/construct/JavassistDemo2");
    This code is inserted before constructor com/hope/javassistapp/construct/JavassistDemo2
    JavassistDemo2:自身构造函数输出内容
    This code is inserted after constructor com/hope/javassistapp/construct/JavassistDemo2
    System.out.println("This code is inserted before constructor java/lang/Shutdown");
    System.out.println("This code is inserted after constructor java/lang/Shutdown");
    System.out.println("This code is inserted before constructor java/lang/Shutdown$Lock");
    System.out.println("This code is inserted after constructor java/lang/Shutdown$Lock");
    This code is inserted before constructor java/lang/Shutdown$Lock
    This code is inserted before constructor java/lang/Shutdown$Lock
    This code is inserted after constructor java/lang/Shutdown$Lock
    This code is inserted after constructor java/lang/Shutdown$Lock
    This code is inserted before constructor java/lang/Shutdown$Lock
    This code is inserted before constructor java/lang/Shutdown$Lock
    This code is inserted after constructor java/lang/Shutdown$Lock
    This code is inserted after constructor java/lang/Shutdown$Lock

    输出结果中,黄色高亮部分是动态增加的代码造成的效果。

    AgentDemo和AgentTransformer是agent工程下的,用于动态修改类使用。

    package com.hope.agent;
    
    import java.lang.instrument.Instrumentation;
    
    import com.hope.transform.AgentTransformer;
    
    /**
     * java agent 入口
     * @author hp
     *
     */
    public class AgentDemo {
    
        public static void premain(String args, Instrumentation inst) {
            inst.addTransformer(new AgentTransformer());
        }
    }
    AgentDemo
    package com.hope.transform;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.lang.instrument.ClassFileTransformer;
    import java.lang.instrument.IllegalClassFormatException;
    import java.security.ProtectionDomain;
    
    import javassist.CannotCompileException;
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtConstructor;
    import javassist.LoaderClassPath;
    
    /**
     * 对类字节码转译
     * @author hp
     *
     */
    public class AgentTransformer implements ClassFileTransformer {
    
        @Override
        public byte[] transform(ClassLoader loader, String className,
                Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
                byte[] classfileBuffer) throws IllegalClassFormatException {
            /**
             * 此处使用javassist API对classfileBuffer进行修改
             */
            ClassPool pool = new ClassPool(true);
            pool.appendClassPath(new LoaderClassPath(loader));
            try {
                CtClass cls = pool.makeClass(new ByteArrayInputStream(classfileBuffer));
                
                //获取构造函数数组
                CtConstructor[] ccs = cls.getDeclaredConstructors();
                //构造函数方法体开始时添加的代码
                String codeStrBefore = "System.out.println("This code is inserted before constructor "+className+"");";
                System.out.println(codeStrBefore);
                //构造函数方法体结束前添加的代码
                String codeStrAfter = "System.out.println("This code is inserted after constructor "+className+"");";
                System.out.println(codeStrAfter);
                for (CtConstructor cc : ccs) {
                    cc.insertBefore(codeStrBefore);
                    cc.insertAfter(codeStrAfter, true);
                }
                return cls.toBytecode();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (RuntimeException e) {
                e.printStackTrace();
            } catch (CannotCompileException e) {
                e.printStackTrace();
            }
            
            return null;
        }
    
    }
    AgentTransformer

    App和JavassistDemo1、JavassistDemo2用于demo演示使用

    package com.hope.javassistapp.app;
    
    import com.hope.javassistapp.construct.JavassistDemo1;
    import com.hope.javassistapp.construct.JavassistDemo2;
    
    public class App {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            JavassistDemo1 d1 = new JavassistDemo1();
            JavassistDemo2 d2 = new JavassistDemo2();
        }
    
    }
    App
    package com.hope.javassistapp.construct;
    
    public class JavassistDemo1 {
    
        public JavassistDemo1() {
            
            
            System.out.println("JavassistDemo1:自身构造函数输出内容");
            
            
        }
    }
    JavassistDemo1
    package com.hope.javassistapp.construct;
    
    public class JavassistDemo2 {
    
        public JavassistDemo2() {
            
            
            System.out.println("JavassistDemo2:自身构造函数输出内容");
            
            
        }
    }
    JavassistDemo2

    对于javassist目前探索到这里,日后还会继续加深对其理解和使用,敬请期待。

    欢迎业内人士交流经验。

  • 相关阅读:
    Notepadd ++ PluginManager安装
    Srping cloud Ribbon 自定义负载均衡
    Spring cloud Eureka 和 Zookeeper 比较
    Spring cloud info信息显示
    kafka 在Windows端安装 找不到或无法加载主类 的解决方案
    Linux kafka 单机安装
    mina
    @bzoj
    @51nod
    @topcoder
  • 原文地址:https://www.cnblogs.com/orionhp/p/6362615.html
Copyright © 2011-2022 走看看