housemd源码解析

1.1准备工作

1.1.1 java agent , java attach api, VirtualMachine 等

java agent代理和 virtualMachine的知识,可以参考 http://blog.csdn.net/qyongkang/article/details/7765255  大概有连续6篇文章.看完的话大概能明白几个概念了.

还有一个简单的例子 http://chenjingbo.iteye.com/blog/1966733  含金量不高 ,不过也可以将就看看.

 

1.1.2 scala 学习

housemd大部分的代码都是用scala写的.所以至少能读懂里面大概什么内容. 拿来主义,看这个吧 http://chenjingbo.iteye.com/blog/1974335

 

1.1.3  jenv

housemd下载是通过jenv的.很方便,一行命令搞定.当然使用jenv使用之前需要安装jenv.也很简单.这个不需要学习,只需要安装一下就好了 ,具体如下 https://github.com/linux-china/jenv/wiki/Chinese-Introduction 

 

1.1.4 yascli

这个包.是一个scala的命令行开发包.具体的地址是 https://github.com/CSUG/yascli

 老实说,我没有完全读透立面的代码,就当一个简单的工具看了.

1.1.5 asm

这个字节码修改工具,如果只是看看housemd的主流程,那么就不需要仔细研究了.如果想看trace命令这种需要修改字节码实现的,是如何工作的,那再仔细学习吧.

 

1.2  正文

1.2.1 housemd的官方地址

housemd的地址在 https://github.com/CSUG/HouseMD 具体的用法就不在这个文档里说明了.看一下 https://github.com/CSUG/HouseMD/wiki/UserGuideCN 就已经非常清楚明白了.

 

1.2.2程序入口

Housemd的使用,最开始当然是在终端里里输入 

terminal 写道
housemd $PID

 直接看 housemd命令对应的代码.

#!/bin/sh
if [ -z "$JAVA_HOME" ];
then
    echo "Please set JAVA_HOME to JDK 6+!"
    exit 1
else
    ROOT=`dirname  "$0"`
    if [ -f $JAVA_HOME/lib/tools.jar ]; then
            BOOT_CLASSPATH=-Xbootclasspath/a:$JAVA_HOME/lib/tools.jar
    fi
    $JAVA_HOME/bin/java $BOOT_CLASSPATH -jar $ROOT/housemd_2.9.2-0.2.6.min.jar "$@"
fi

 这里非常简单,只是把tools.jar设置成boot_classpath,然后执行执行 java -jar 命令运行housemd对应的jar. 既然如此,直接看对应的METAINF.MF .

Manifest-Version: 1.0
Implementation-Title: housemd
Implementation-Version: 0.2.6
Specification-Vendor: com.github.zhongl
Implementation-Vendor: com.github.zhongl
Implementation-Vendor-Id: com.github.zhongl
Specification-Title: housemd
Agent-Class: com.github.zhongl.housemd.duck.Duck
Specification-Version: 0.2.6
Main-Class: com.github.zhongl.housemd.house.House
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Signature-Version: 0.2.6

 这个文件,后续还需要用到.这里我们需要关心的是 

写道
Main-Class: com.github.zhongl.housemd.house.House

 这样,我们就找到对应的入口class了.

 

 1.2.3 House.scala

这个类里核心代码如下

def run() {
    if (printVersion()) {//如果只是打印版本,直接打印版本号
      println("v" + version)
      return
    }
//如果是windows系统,直接返回说不支持.
    if (ManagementFactory.getOperatingSystemMXBean.getName.toLowerCase.contains("window")) {
      throw new IllegalStateException("Sorry, Windows is not supported now.")
    }
    try {
//创建一个内置的unix terminal 这个都是scala的独有类,不多说了.功能就是内置unix terminal.
      val terminal = new NoInterruptUnixTerminal()
      terminal.init()
      val sout = terminal.wrapOutIfNeeded(System.out)
      val sin = terminal.wrapInIfNeeded(System.in)
      val vm = VirtualMachine.attach(pid())

      val mobilephone = new Mobilephone(port(), {
        case PickUp              => info("connection established on " + port())
        case ListenTo(earphone)  => earphone(sout)
        case SpeakTo(microphone) => microphone(sin)
        case BreakOff(reason)    => error("connection breaked causeby"); error(reason)
        case HangUp              => terminal.restore(); silentClose(errorDetailWriter); info("bye")

      })

      info("Welcome to HouseMD " + version)
//核心代码在这里.下面会仔细说明.
      vm.loadAgent(agentJarFile, agentOptions mkString " ")
      vm.detach()

      mobilephone.start()
    } catch {
      case e: Throwable => error(e); silentClose(errorDetailWriter)
    }
  }
一些非主要的功能,上面已经通过注释说明了.其中核心的代码是 
val vm = VirtualMachine.attach(pid()) //pid()就是获取传入的pid
      vm.loadAgent(agentJarFile, agentOptions mkString " ")
      vm.detach()
 可以看到,他也是通过VirtualMachine load 对应的agent来实现功能的..我们再仔细看一下对应的参数.

我们知道 VirtualMachine.loadAgent 方法,第一个参数是对应agent的jar包全路径,第二个参数是给agent传入的参数.

private lazy val agentJarFile = sourceOf(Manifest.classType(getClass))
 housemd一共就一个jar包,也就是说,当前的class所在的jar地址就是对应agent所在的地址..sourceOf方法就是获取当前类所在的jar包地址.
private lazy val agentOptions = agentJarFile :://agent所在的jar包全路径
                                  classNameOf[Telephone] :: //Telephone对应的全额类目.这个类后续会具体说
                                  port() :://内置的terminal 开启的服务的端口号.
                                  classNameOf[Trace] :://后面的6个就是housemd对应支持的命令,每个命令对应一个类.
                                  classNameOf[Loaded] ::
                                  classNameOf[Env] ::
                                  classNameOf[Inspect] ::
                                  classNameOf[Prop] ::
                                  classNameOf[Resources] ::
                                  Nil  //what's this 
 后面的参数比较多.里面的参数内容,我大概都解释了.每个参数中间用空格隔开.这里的参数内容解释,后面都会用到. 好了.上面把程序入口的代码都解释了一遍.里面核心的就是attach agent了.下面,就需要看对应的agent class在哪呢.查看上面的METAINF.MF ,可以看到
写道
Agent-Class: com.github.zhongl.housemd.duck.Duck
 OK.下面继续看对应的agent class 1.2.4 Duck

猜你喜欢

转载自chenjingbo.iteye.com/blog/1974799