在之前android的性能监测sdk项目中用到过asm库,在这里记录一下基本原理和用法;

ASM库/工具  http://asm.ow2.org/

ASM是一款基于java字节码层面的代码分析和修改工具;无需提供源代码即可对应用嵌入所需debug代码,用于应用API性能分析,代码优化和代码混淆等工作。ASM的目标是生成,转换和分析已编译的java class文件,可使用ASM工具读/写/转换JVM指令集。

ASM工具提供两种方式来产生和转换已编译的class文件,它们分别是基于事件和基于对象的表示模型。其中,基于事件的表示模型使用一个有序的事件序列表示一个class文件,class文件中的每一个元素使用一个事件来表示,比如class的头部,变量,方法声明,JVM指令都有相对应的事件表示,ASM使用自带的事件解析器能将每一个class文件解析成一个事件序列。而基于对象的表示模型则使用对象树结构来解析每一个class文件。


Java生成asmx服务 java asm教程_抽象类

基于事件模型的ASM工具使用生产者-消费者模型转换/产生一个class文件。其转换过程中涉及到自定义的事件生产者,自定义的事件过滤器和自定义的事件消费者这三种组件。其中使用classReader来解析每一个class文件中的事件元素,使用自定义的各种基于方法/变量/声明/类注释的元素适配器来过滤和修改class事件元序列中的相应事件对象,最后使用ClassWriter来重新将更新后的class事件序列转换成class字节码供JVM加载执行。整个生产/转换class文件的过程如下图所示,起点和终点分别是ClassReader(Class文件解析器)和ClassWriter(class事件序列转换到class字节码),中间的过程由若干个自定义的事件过滤器组成。

1.1、class文件的结构
class文件保持固定的结构信息,而且保留了几乎所有的源代码文件中的符号。一个class文件整体结构由几个区域组成,一个区域用来描述类的modifier,name,父类,接口和注释。一个区域用来描述类中变量的modfier,名字,类型和注释。一个区域用来描述类中方法和构造函数的modifier,名字参数类型,返回类型,注释等信息,当然也包含已编译成java字节码指令序列的方法具体内容。还有一个作为class文件的静态池区域,用来保存所有的数字,字符串,类型的常量,这些常量只被定义过一次且被其他class中区域所引用。class文件与源代码文件的关系:一个java文件最后会被编译成N(1 <= N)个class文件。
下图展示了一个class文件的总体概貌


Java生成asmx服务 java asm教程_抽象类_02

图 1.1 class文件的概览(*表示0个或者多个)

1.2、 class文件的内部命名
原java类型与class文件内部类型对应关系


Java生成asmx服务 java asm教程_抽象类_03

图1.2 java类型的描述

        原java方法声明与class文件内部方法声明的对应关系


Java生成asmx服务 java asm教程_java_04

图1.3方法描述举例

1.3、ASM工具的接口和组件
ASM工具生产和转换class文件内容的所有工作都是基于ClassVisitor这个抽象类进行的。ClassVisitor抽象类中的每一个方法会对应到class文件的相应区域,每个方法负责处理class文件相应区域的字节码内容。下图展示了ClassVisitor抽象类的成员函数。






public                   abstract                   class                   ClassVisitor                   {


             public                   ClassVisitor         (         int                   api         )         ;


             public                   ClassVisitor         (         int                   api         ,                   ClassVisitor          cv         )         ;


             public                   void                   visit         (         int                   version         ,                   int                   access         ,                   String                   name         ,                   String                   signature         ,                   String                   superName         ,                   String         [         ]                   interfaces         )         ;


             public                   void                   visitSource         (         String                   source         ,                   String                   debug         )         ;


             public                   void                   visitOuterClass         (         String                   owner         ,                   String                   name         ,                   String                   desc         )         ;          


             AnnotationVisitor          visitAnnotation         (         String                   desc         ,                   boolean                   visible         )         ;          


             public                   void                   visitAttribute         (         Attribute          attr         )         ;


             public                   void                   visitInnerClass         (         String                   name         ,                   String                   outerName         ,                   String                   innerName         ,                   int                   access         )         ;


             public                   FieldVisitor          visitField         (         int                   access         ,                   String                   name         ,                   String                   desc         ,


             String                   signature         ,                   Object                   value         )         ;


             public                   MethodVisitor          visitMethod         (         int                   access         ,                   String                   name         ,                   String                   desc         ,                   String                   signature         ,                   String         [         ]                   exceptions         )         ;          


             void                   visitEnd         (         )         ;


}



某些区域方法直接完成该区域字节码内容的处理并返回空,某些复杂class区域的方法需返回更加细节的XXXVisitor对象,此XXXVisitor对象将负责处理此class区域的更加细节的字节码内容,开发者可以编写继承自XXXVisitor抽象类的自定义类,在成员函数中实现对细节字节码操作的逻辑代码。比如,visitField方法用来负责class文件中变量区域的字节码内容修改,该区域又可细分出多种属性数据对象(注释,参数值),这里需要编写继承自fieldVisitor抽象类的自定义类完成这些细分数据对象的字节码内容操作。下图为FieldVisitor的抽象类内容。






public                   abstract                   class                   FieldVisitor                   {


             public                   FieldVisitor         (         int                   api         )         ;


             public                   FieldVisitor         (         int                   api         ,                   FieldVisitor          fv         )         ;


             public                   AnnotationVisitor          visitAnnotation         (         String                   desc         ,                   boolean                   visible         )         ;          


             public                   void                   visitAttribute         (         Attribute          attr         )         ;


             public                   void                   visitEnd         (         )         ;


}


另外,在处理整个class文件处理过程中,classVistor抽象类中的方法访问需满足下面的次序。
visitvisitSource? visitOuterClass? ( visitAnnotation | visitAttribute )*
(visitInnerClass | visitField | visitMethod )*
visitEnd
基于ClassVistor api的访问方式,ASM工具提供了三种核心组件用来实现class的产生和转换工作。ClassReader负责解析class文件字节码数组,然后将相应区域的内容对象传递给classVistor实例中相应的visitXXX方法,ClassReader可以看作是一个事件生产者。ClassWriter继承自ClassVistor抽象类,负责将对象化的class文件内容重构成一个二进制格式的class字节码文件,ClassWriter可以看作是一个事件消费者。继承自ClassVistor抽象类的自定义类负责class文件各个区域内容的修改和生成,它可以看作是一个事件过滤器,一次生产消费过程中这样的事件过滤器可以有N个(0<=N)。

1.3.1、遍历CLASS字节码类信息
面的例子用来打印class字节码内容的类信息,这里以java.lang.runnable为例。
test.java:






public                   class                   ClassPrinter                   extends                   ClassVisitor                   {          


             public                   ClassPrinter         (         )                   {


                 super         (         ASM4         )         ;


             }


             public                   void                   visit         (         int                   version         ,                   int                   access         ,                   String                   name         ,                   String                   signature         ,                   String                   superName         ,                   String         [         ]                   interfaces         )                   {


                 System         .         out         .         println         (         name                   +                   " extends "                   +                   superName                   +                   " {"         )         ;


             }


             public                   void                   visitSource         (         String                   source         ,                   String                   debug         )                   {         }


             public                   void                   visitOuterClass         (         String                   owner         ,                   String                   name         ,                   String                   desc         )                   {         }


             public                   AnnotationVisitor          visitAnnotation         (         String                   desc         ,                   boolean                   visible         )                   {


                 return                   null         ;


             }


             public                   void                   visitAttribute         (         Attribute          attr         )                   {         }


             public                   void                   visitInnerClass         (         String                   name         ,                   String                   outerName         ,                   String                   innerName         ,                   int                   access         )                   {         }


             public                   FieldVisitor          visitField         (         int                   access         ,                   String                   name         ,                   String                   desc         ,                   String                   signature         ,                   Object                   value         )                   {


                 System         .         out         .         println         (         "    "                   +                   desc                   +                   " "                   +                   name         )         ;


                 return                   null         ;


             }


             public                   MethodVisitor          visitMethod         (         int                   access         ,                   String                   name         ,                   String                   desc         ,                   String                   signature         ,                   String         [         ]                   exceptions         )                   {


                 System         .         out         .         println         (         " "                   +                   name                   +                   desc         )         ;


                 return                   null         ;


             }


             public                   void                   visitEnd         (         )                   {


                 System         .         out         .         println         (         "}"         )         ;


             }          


}


                  


//ClassReader作为字节码生产者,ClassPrinter作为字节码消费者


ClassPrinter          cp                   =                   new                   ClassPrinter         (         )         ;


ClassReader          cr                   =                   new                   ClassReader         (         "java.lang.Runnable"         )         ;


cr         .         accept         (         cp         ,                   0         )         ;


输出:






java         /         lang         /         Runnable                   extends                   java         /         lang         /         Object                   {


             run         (         )         V


}


1.3.2、生产自定义类对应的class字节码内容
目标生产出以下自定义接口:





package                   pkg         ;


public                   interface                   Comparable                   extends                   Mesurable                   {


             int                   LESS                   =                   -         1         ;


             int                   EQUAL                   =                   0         ;


             int                   GREATER                   =                   1         ;


             int                   compareTo         (         Object                   o         )         ;


}


test.java内容:





ClassWriter          cw                   =                   new                   ClassWriter         (         0         )         ;


cw         .         visit         (         V1_5         ,                   ACC_PUBLIC                   +                   ACC_ABSTRACT                   +                   ACC_INTERFACE         ,                   "pkg/Comparable"         ,                   null         ,                   "java/lang/Object"         ,                   new                   String         [         ]                   {                   "pkg/Mesurable"                   }         )         ;


cw         .         visitField         (         ACC_PUBLIC                   +                   ACC_FINAL                   +                   ACC_STATIC         ,                   "LESS"         ,                   "I"         ,                   null         ,                   new                   Integer         (         -         1         )         )         .         visitEnd         (         )         ;


cw         .         visitField         (         ACC_PUBLIC                   +                   ACC_FINAL                   +                   ACC_STATIC         ,                   "EQUAL"         ,                   "I"         ,                   null         ,                   new                   Integer         (         0         )         )         .         visitEnd         (         )         ;


cw         .         visitField         (         ACC_PUBLIC                   +                   ACC_FINAL                   +                   ACC_STATIC         ,                   "GREATER"         ,                   "I"         ,                   null         ,                   new                   Integer         (         1         )         )         .         visitEnd         (         )         ;                   cw         .         visitMethod         (         ACC_PUBLIC                   +                   ACC_ABSTRACT         ,                   "compareTo"         ,                   "(Ljava/lang/Object;)I"         ,                   null         ,                   null         )         .         visitEnd         (         )         ;                   cw         .         visitEnd         (         )         ;


byte         [         ]                   b                   =                   cw         .         toByteArray         (         )         ;


1.3.3、动态加载1.3.2生产出的class字节码并实例化该类
使用继承自ClassLoader的类,并重写defineClass方法;
test.java:





//第一种方法:通过ClassLoader的defineClass动态加载字节码


class                   MyClassLoader                   extends                   ClassLoader                   {


             public                   Class                   defineClass         (         String                   name         ,                   byte         [         ]                   b         )                   {


                 return                   defineClass         (         name         ,                   b         ,                   0         ,                   b         .         length         )         ;


             }


}


//直接调用方法


Class                   c                   =                   myClassLoader         .         defineClass         (         "pkg.Comparable"         ,                   b         )         ;



使用继承自ClassLoader的类,并重写findClass内部类;
test.java:






class                   StubClassLoader                   extends                   ClassLoader                   {


             @Override


             protected                   Class                   findClass         (         String                   name         )                   throws                   ClassNotFoundException                   {


                 if                   (         name         .         endsWith         (         "_Stub"         )         )                   {


                     ClassWriter          cw                   =                   new                   ClassWriter         (         0         )         ;


.         .         .


byte         [         ]                   b                   =                   cw         .         toByteArray         (         )         ;


                     return                   defineClass         (         name         ,                   b         ,                   0         ,                   b         .         length         )         ;


                 }


                 return                   super         .         findClass         (         name         )         ;


             }


}


1.3.4、转换class字节码内容中类的成员(变量,方法,注释等)
1.3.4.1、ClassReader生产者生产的class字节码bytes可以被ClassWriter直接消费,比如:






byte         [         ]                   b1                   =                   .         .         .         ;


ClassWriter          cw                   =                   new                   ClassWriter         (         0         )         ;


ClassReader          cr                   =                   new                   ClassReader         (         b1         )         ;


cr         .         accept         (         cw         ,                   0         )         ;


byte         [         ]                   b2                   =                   cw         .         toByteArray         (         )         ;                   //这里的b2与b1表示同一个类且值一样


1.3.4.2、ClassReader生产者生产的class字节码bytes可以先被继承自ClassVisitor的自定义类过滤,最后被ClassWriter消费,比如:






byte         [         ]                   b1                   =                   .         .         .         ;


ClassWriter          cw                   =                   new                   ClassWriter         (         0         )         ;


// cv forwards all events to cw


ClassVisitor          cv                   =                   new                   ChangeVersionAdapter                   (         cw         )                   {                   }         ;


ClassReader          cr                   =                   new                   ClassReader         (         b1         )         ;


cr         .         accept         (         cv         ,                   0         )         ;


byte         [         ]                   b2                   =                   cw         .         toByteArray         (         )         ;                   //这里的b2与b1表示同一个类但值不一样


具体架构图如下如所示,


Java生成asmx服务 java asm教程_Java生成asmx服务_05

图1.6类字节码转换链(bytes->reader->adapter->writer->bytes)

这里的ChangeVersionAdapter继承自ClassVisitor,它没做其他过滤,仅仅重写了visit方法,过滤出类中的方法并指定方法的版本号(v1.5)。






public                   class                   ChangeVersionAdapter                   extends                   ClassVisitor                   {          


             public                   ChangeVersionAdapter         (         ClassVisitor          cv         )                   {


                 super         (         ASM4         ,                   cv         )         ;


             }


             @Override


             public                   void                   visit         (         int                   version         ,                   int                   access         ,                   String                   name         ,                   String                   signature         ,                   String                   superName         ,                   String         [         ]                   interfaces         )                   {          


                 cv         .         visit         (         V1_5         ,                   access         ,                   name         ,                   signature         ,                   superName         ,                   interfaces         )         ;


             }          


}


整个字节码转换过程的时序图如下所示。

Java生成asmx服务 java asm教程_Java生成asmx服务_06

图1.7类字节码使用ChangeVersionAdapter过滤转换过程的时序图

通过重写ClassVisitor的visit方法并修改cv.visit方法中的其他参数,你还能做其他有趣的事情。比如,你能给这个class增加一个接口,改变这个class的名字等。

1.3.4.3、如何使用转换过的class类字节码
前面的小节提到,转换后的class b2能够保存到磁盘中或者通过ClassLoader动态加载。通过这种动态加载的方式只能在本地使用这个ClassLoader加载的单个类,无法满足同时加载多个类的需求。如果你想要转换所有运行时的类字节码并能够加载使用这些转换后的类字节码文件(被systemClassLoader加载),你需要使用java.lang.instrument包中的ClassFileTransformer类。实现继承自ClassFileTransformer的自定义类并重写transform方法,在该方法中实现对所有系统class文件的遍历(这里的遍历指对各个class文件在字节码层面的转换)。另外这里的ClassFileTransformer必须在main方法之前完成class文件的转换,且必须与main方法在同一个JVM中运行,这样才能被system classLoader加载。
那么怎么实现字节码转换发生在main方法执行之前?这里涉及到java agent的概念,java代理(agent) 作为main方法前的一个拦截器 (interceptor),也就是在main方法执行之前,执行agent的代码。agent的代码与你的main方法在同一个JVM中运行,并被同一个system classloader装载,被同一的安全策略 (security policy) 和上下文 (context) 所管理。
怎样写一个java agent? 只需要实现premain这个方法
public static void premain(String agentArgs,Instrumentation inst)
下面的例子展示了如何实现对所有运行时class字节码进行转换并加载的方法。






public                   static                   void                   premain         (         String                   agentArgs         ,                   Instrumentation          inst         )                   {         //该方法在main方法前运行


             inst         .         addTransformer         (         new                   ClassFileTransformer         (         )                   {


                 public                   byte         [         ]                   transform         (         ClassLoader                   l         ,                   String                   name         ,                   Class                   c         ,                   ProtectionDomain                   d         ,                   byte         [         ]                   b         )                   throws                   IllegalClassFormatException                   {


                     ClassReader          cr                   =                   new                   ClassReader         (         b         )         ;


                     ClassWriter          cw                   =                   new                   ClassWriter         (         cr         ,                   0         )         ;


                     ClassVisitor          cv                   =                   new                   ChangeVersionAdapter         (         cw         )         ;


                     cr         .         accept         (         cv         ,                   0         )         ;


                     return                   cw         .         toByteArray         (         )         ;


                 }          


             }         )         ;


}


1.3.5、删除class中的方法或者变量的做法
通过在visitMethod或者visitField方法中返回null的方式就能实现删除class中的方法或者变量的需求。如下实例,通过传入名字和描述删除class中的相应方法。





public                   class                   RemoveMethodAdapter                   extends                   ClassVisitor                   {


             private                   String                   mName         ;


             private                   String                   mDesc         ;


             public                   RemoveMethodAdapter         (         ClassVisitor          cv         ,                   String                   mName         ,                   String                   mDesc         )                   {


                 super         (         ASM4         ,                   cv         )         ;


                 this         .         mName                   =                   mName         ;


                 this         .         mDesc                   =                   mDesc         ;


             }


             @Override


             public                   MethodVisitor          visitMethod         (         int                   access         ,                   String                   name         ,                   String                   desc         ,                   String                   signature         ,                   String         [         ]                   exceptions         )                   {


                 if                   (         name         .         equals         (         mName         )                   &&                   desc         .         equals         (         mDesc         )         )                   {


                     // do not delegate to next visitor -> this removes the method


                     return                   null         ;


                 }


                 return                   cv         .         visitMethod         (         access         ,                   name         ,                   desc         ,                   signature         ,                   exceptions         )         ;


             }


}


1.3.6、增加class中的方法或者变量的做法
在visitEnd中增加想要增加的方法或者变量,实例如下。






public                   class                   AddFieldAdapter                   extends                   ClassVisitor                   {


             private                   int                   fAcc         ;


             private                   String                   fName         ;


             private                   String                   fDesc         ;


             private                   boolean                   isFieldPresent         ;


             public                   AddFieldAdapter         (         ClassVisitor          cv         ,                   int                   fAcc         ,                   String                   fName         ,                   String                   fDesc         )                   {


                 super         (         ASM4         ,                   cv         )         ;


                 this         .         fAcc                   =                   fAcc         ;


                 this         .         fName                   =                   fName         ;


                 this         .         fDesc                   =                   fDesc         ;


             }


             @Override


             public                   FieldVisitor          visitField         (         int                   access         ,                   String                   name         ,                   String                   desc         ,                   String                   signature         ,                   Object                   value         )                   {


                 if                   (         name         .         equals         (         fName         )         )                   {


                     isFieldPresent                   =                   true         ;


                 }


                 return                   cv         .         visitField         (         access         ,                   name         ,                   desc         ,                   signature         ,                   value         )         ;


             }


             @Override


             public                   void                   visitEnd         (         )                   {


                 if                   (         !         isFieldPresent         )                   {


                     FieldVisitor          fv                   =                   cv         .         visitField         (         fAcc         ,                   fName         ,                   fDesc         ,                   null         ,                   null         )         ;


                     if                   (         fv                   !=                   null         )                   {


                         fv         .         visitEnd         (         )         ;


                     }


                 }


                 cv         .         visitEnd         (         )         ;


             }


}


1.3.7、classVisitor过滤(转换)链
可在一次 生产—过滤–消费 过程中,使用多个继承自classVisitor的自定义过滤类对class进行过滤(转换)。


Java生成asmx服务 java asm教程_字节码_07

图2.8过滤链

下面的实例中通过传入多个自定义的过滤器,实现过滤链的功能。





public                   class                   MultiClassAdapter                   extends                   ClassVisitor                   {                   protected                   ClassVisitor         [         ]                   cvs         ;


             public                   MultiClassAdapter         (         ClassVisitor         [         ]                   cvs         )                   {


                 super         (         ASM4         )         ;


                 this         .         cvs                   =                   cvs         ;


             }


             @Override                   public                   void                   visit         (         int                   version         ,                   int                   access         ,                   String                   name         ,                   String                   signature         ,                   String                   superName         ,                   String         [         ]                   interfaces         )                   {


                 for                   (         ClassVisitor          cv                   :                   cvs         )                   {


                     cv         .         visit         (         version         ,                   access         ,                   name         ,                   signature         ,                   superName         ,                   interfaces         )         ;


                 }


             }


             .         .         .          


}


1.3.8、最后通过一个例子来梳理一下asm工具的使用方法
例子中用到了agentmain,先补充一下相关知识。
agentmain方式
premain时JavaSE5开始就提供的代理方式,给了开发者诸多惊喜,不过也有些须不变,由于其必须在命令行指定代理jar,并且代理类必须在main方法前启动。因此,要求开发者在应用前就必须确认代理的处理逻辑和参数内容等等,在有些场合下,这是比较苦难的。比如正常的生产环境下,一般不会开启代理功能,但是在发生问题时,我们不希望停止应用就能够动态的去修改一些类的行为,以帮助排查问题,这在应用启动前是无法确定的。 为解决运行时启动代理类的问题,JavaSE6开始,提供了在应用程序的VM启动后在动态添加代理的方式,即agentmain方式。 与permain类似,agent方式同样需要提供一个agentjar,并且这个jar需要满足:
1. 在manifest中指定Agent-Class属性,值为代理类全路径
2. 代理类需要提供public static voidagentmain(String args, Instrumentation inst)或public static void agentmain(Stringargs)方法。并且再二者同时存在时以前者优先。args和inst和premain中的一致。
不过如此设计的再运行时进行代理有个问题——如何在应用程序启动之后再开启代理程序呢?JDK6中提供了JavaTools API,其中AttachAPI可以满足这个需求。
Attach API中的VirtualMachine代表一个运行中的VM。其提供了loadAgent()方法,可以在运行时动态加载一个代理jar。具体需要参考《Attach API》(http://docs.oracle.com/javase/6/docs/jdk/api/attach/spec/com/sun/tools/attach/VirtualMachine.html)

完整的例子如下,在java.lang.ProcessBuilder实例调用start方法时eclipse的console中打印出”java.lang.ProcessBuilder实例的start方法被触发”。
代理类RewriterAgent.java:






public                   class                   RewriterAgent                   {


                  


             public                   static                   void                   agentmain         (         String                   agentArgs         ,                   Instrumentation          instrumentation         )         {                   //代理类入口函数


                 premain         (         agentArgs         ,                   instrumentation         )         ;


             }


                  


             public                   static                   void                   premain         (         String                   agentArgs         ,                   Instrumentation          instrumentation         )         {                   //代理类入口函数Java SE6


                  


                 try         {


                     DexClassTransformer          dexClassTransformer                   =                   new                   DexClassTransformer         (         )         ;                   //继承自ClassFileTransformer的自定义类,多class文件的加载


                     instrumentation         .         addTransformer         (         dexClassTransformer         ,                   true         )         ;          


                 }


                 catch         (         Throwable          ex         )         {


                     System         .         out         .         println         (         "Agent startup error"         )         ;


                     throw                   new                   RuntimeException         (         ex         )         ;


                 }


             }


                  


             private                   static                   final                   class                   DexClassTransformer                   implements                   ClassFileTransformer         {


                 private                   Log          log         ;


                 private                   final                   Map          classVisitors         ;


                  


                 public                   byte         [         ]                   transform         (         ClassLoader          classLoader         ,                   String                   className         ,                   Class                   clazz         ,                   ProtectionDomain          protectionDomain         ,                   byte                   bytes         [         ]         )                   throws                   IllegalClassFormatException         {


                     ClassVisitorFactory          factory                   =                   (         ClassVisitorFactory         )         classVisitors         .         get         (         className         )         ;                   //根据给定className匹配相应class的工厂对象


                     if         (         factory                   !=                   null         )         {


                         if         (         clazz                   !=                   null                   &&                   !         factory         .         isRetransformOkay         (         )         )         {


                             return                   null         ;


                         }


                         try         {


                             ClassReader          cr                   =                   new                   ClassReader         (         bytes         )         ;                    //生产者


                             ClassWriter          cw                   =                   new                   PatchedClassWriter         (         3         ,                   classLoader         )         ;                   //消费者 自定义的ClassWriter


                             ClassAdapter          adapter                   =                   factory         .         create         (         cw         )         ;                   //过滤器


                             cr         .         accept         (         adapter         ,                   4         )         ;


                             return                   cw         .         toByteArray         (         )         ;


                         }


                         catch         (         SkipException          ex         )                   {                   }


                         catch         (         Exception          ex         )         {


                             throw                   ex         ;


                         }


                     }


                     return                   null         ;


                 }


        


                 public                   DexClassTransformer         (         )                   throws                   URISyntaxException         {


                     classVisitors                   =                   new                   HashMap         <         String         ,                   ClassVisitorFactory         >         (         )         {                    //将需要转换的类放到map中,Map中为不同的类指定相应的工厂对象


                         private                   static                   final                   long                   serialVersionUID                   =                   1L         ;


                         {


                             put         (         "java/lang/ProcessBuilder"         ,                   new                   ClassVisitorFactory         (         true         )         {                   //实现ClassVisitorFactory并重写create方法


                                 public                   ClassAdapter          create         (         ClassVisitor          cv         )         {


                                     return                   RewriterAgent         .         createProcessBuilderClassAdapter         (         cv         )         ;


                                 }


                             }         )         ;


                         }


                     }         ;


                 }


             }
private                   static                   ClassAdapter          createProcessBuilderClassAdapter         (         ClassVisitor          cw         ,                   Log          log         )         {


                 return                   new                   ClassAdapter         (         cw         )         {


                     public                   MethodVisitor          visitMethod         (         int                   access         ,                   String                   name         ,                   String                   desc         ,                   String                   signature         ,                   String                   exceptions         [         ]         )         {


                         MethodVisitor          mv                   =                   super         .         visitMethod         (         access         ,                   name         ,                   desc         ,                   signature         ,                   exceptions         )         ;


                         if         (         "start"         .         equals         (         name         )         )         {


                             System         .         out         .         println         (         "java.lang.ProcessBuilder实例的start方法被触发"         )         ;


                         }


                         return                   mv         ;


                     }


                 }         ;


             }


}


自定义的ClassWriter:






class                   PatchedClassWriter                   extends                   ClassWriter         {


             private                   final                   ClassLoader          classLoader         ;


                  


             public                   PatchedClassWriter         (         int                   flags         ,                   ClassLoader          classLoader         )         {


                 super         (         flags         )         ;


                 this         .         classLoader                   =                   classLoader         ;


             }


                  


             protected                   String                   getCommonSuperClass         (         String                   type1         ,                   String                   type2         )         {                   //返回共同的父类


                 Class                   c         ;


                 Class                   d         ;


                 try         {


                     c                   =                   Class         .         forName         (         type1         .         replace         (         '/'         ,                   '.'         )         ,                   true         ,                   classLoader         )         ;


                     d                   =                   Class         .         forName         (         type2         .         replace         (         '/'         ,                   '.'         )         ,                   true         ,                   classLoader         )         ;


                 }


                 catch         (         Exception                   e         )         {


                     throw                   new                   RuntimeException         (         e         .         toString         (         )         )         ;


                 }


                 if         (         c         .         isAssignableFrom         (         d         )         )


                     return                   type1         ;


                 if         (         d         .         isAssignableFrom         (         c         )         )


                     return                   type2         ;


                 if         (         c         .         isInterface         (         )                   ||                   d         .         isInterface         (         )         )


                     return                   "java/lang/Object"         ;


                 do


                     c                   =                   c         .         getSuperclass         (         )         ;


                 while         (         !         c         .         isAssignableFrom         (         d         )         )         ;


                 return                   c         .         getName         (         )         .         replace         (         '.'         ,                   '/'         )         ;


             }


}


测试类AttachTest:





public                   class                   AttachTest                   {


             public                   static                   void                   main         (         String         [         ]                   args         )                   throws                   AttachNotSupportedException         ,                   IOException         ,                   AgentLoadException         ,                   AgentInitializationException                   {


                 VirtualMachine          vm                   =                   VirtualMachine         .         attach         (         args         [         0         ]         )         ;         //args[0]传入的是jvm的pid号


                 vm         .         loadAgent         (         "F:\\workspace\\rewriterAgent.jar"         )         ;                   //rewriterAgent.jar是RewriterAgent.java导出的Jar包名


             }


}