使用javassist生成对象转换器Converter

在编程当中,作为Converter, spring体系自带的conversionService可以解决大部分基本对象的转换问题,但对于在业务系统中写的domain,vo,po等对象.spring是不能完成相应对象之间的转换的, 当然也可以使用类似BeanUtils.copyProperties来完成属性之间的数据复制功能. 除此之外,还可以使用第三方组件,比如dozer,都可以进行信息复制处理.

不过上面的方法的问题在于, 除扩展之外,相应的转换过程均是使用反射来完成的.比如通过 PropertyDescriptor 来获取property的readMethod, 然后再通过writeMethod来写入目标对象的数据值,或者直接通过Field.set来完成字段级的数据写入.从编码手法上来看,当前我们更希望通过一些非反射的手法来完成这个操作, 一种实现方法即是通过字节码生成来构建一个特定场景的Converter, 直接通过方法调用来完成相应的映射过程.

一个标准的转换器接口定义如下:

public interface Converter<S, T> {
    T convert(S s);
}

实现者除了要完成具体的convert过程之外, 还需要对外暴露出具体的泛型信息,以方便框架进行读取和解析. 比如spring conversionService即会通过读取converter实现类泛型来完成内部 from -> to的映射过程(而不需要调用者手动进行类型传参).

本文描述了一种通过javassist,字节码操作工具, 动态地读取from,to类的描述信息和注解信息, 完成convert body的字符串生成. 同时, 写入相应的泛型信息, 以实现泛型编程.

继续阅读“使用javassist生成对象转换器Converter”

greys在线诊断工具的主要实现

greys是一个使用java management tool进程注入javaagent实现在线系统的诊断一个工具。原github为(https://github.com/oldmanpushcart/greys-anatomy),其主要的功能在于系统不停机的情况下。可以查看系统中的线程信息,cpu使用情况,jmx信息,以及某个方法在运行时的调用栈,调用参数等。

一个典型的场景就是线上某个功能出bug,但是系统中并没有记录参数信息,这时候即可通过这个功能注入agent,临时地打印出这个调用方法的参数,以方便定位相应的问题。如无此工具,则只能改代码,然后重新上线。在这种情况下,可能出错的场景就不能再复现。(当然也有其它工具(如log monitor)作到在线系统参数记录开关的目的,这里不作描述)

本文主要描述greys是如何工作的,包括如何注入到在线系统,然后脚本client与注入后server端的交互,以及如何实现一个简单的参数拦截记录功能。从整个实现机制层面描述其工作原理。

继续阅读“greys在线诊断工具的主要实现”

使用javassist编写一个简单的agentClassTransformer

前段时间找到一个很好的工具Greys-anatomy, 相应的参考地址为参考地址:https://github.com/oldmanpushcart/greys-anatomy. 为此,专门研究了一下基工作原理.并简单研究了一下基于Instrumentation进行运行时代码调整的一些实现手法. 本文, 简单介绍一下如何使用javassist来简单对一个代码作编织, 实现简单的一些监控指标手段.

附: 另外,前几年淘宝也简单作了一个通过启动时agent达到运行方法监控的目的, 称之为TProfiler,对研究一些实现手法很有用.

一个主要的ClassFileTransformer定义如下:

    byte[]
    transform(  ClassLoader         loader,
                String              className,
                Class<?>            classBeingRedefined,
                ProtectionDomain    protectionDomain,
                byte[]              classfileBuffer)
        throws IllegalClassFormatException;

传递到当前实现的主要有用的信息即为className, classfileBuffer两个数据. className即为当前正准备加载的类, 而classfileBuffer即传递给当前处理的字节码, 需要做的即是将这个字节码进行处理,然后返回一个已经处理过的字节码,即完成instrument操作.

继续阅读“使用javassist编写一个简单的agentClassTransformer”

java内部类final语义实现

本文描述在java内部类中,经常会引用外部类的变量信息。但是这些变量信息是如何传递给内部类的,在表面上并没有相应的线索。本文从字节码层描述在内部类中是如何实现这些语义的。

本地临时变量 基本类型

final int x = 10;

new Runnable() {
    @Override
    public void run() {
        System.out.println(x);
    }
}.run();

当输出内部类字节码(javap -p -s -c -v)时,如下所示:

         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: bipush        10
         5: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
         8: return

可以看出,此常量值直接被写在内部类的临时变量中,即相当于进行了一次变量copy。

继续阅读“java内部类final语义实现”