没有比新增一些更酷的指令, 更让人兴奋的啦~
要办到它, 得从下面的类入手.
Command
像env 这样不需要用到Instrumentation
指令, 可以直接继承Command
, 将自定义指令的逻辑实现在run
方法中.
切记, 指令只能有一个构造器, 因为只有第一个构造器会被用于实例化指令; 并且, 构造器应至少有一个参数是
PrintOut
, 用以Command
的初始化, 它是用来向控制台回显信息的. 不用担心如何构造一个PrintOut
的实例, 只用留好这个参数,HouseMD
会帮我们搞定.
每个指令是如何被执行的呢?
典型的过程是:
- 首先, 每个
Command
的具体实现类会被House引导给Duck并由Telephone来实例化它们, - 在
housemd>
提示下输入一串字符, 按下回车后, 这串字符会被拆分为为指令和其参数选项两个部分, 通过指令部分匹配相应指令的实例, 而参数选项的部分则交由指令实例的parse
方法进行解析, - 解析完成后, 指令实例的
run
方法会被调用
如何声明参数选项
Command
提供了三种方法来实现声明:
flag
声明布尔类型的选项, 通常用于开启什么模式或特定的动作, 例如loaded
指令的-h
选项option
声明除布尔类型之外的单值选项, 选项是必须有默认值的, 例如trace
的-p
选项parameter
声明参数,- 可以声明多个参数, 输入的顺序与声明的顺序一致
- 可以是单值或多值, 多个参数的情况下, 只允许最后一个参数是多值
- 可以设定默认值, 不设的话表明必须要输入参数.
请确保参数选项的声明, 使用在声明属性的位置完成的, 目的是为了保证在执行Command
的parse
方法之前, 所有的声明已完成.
细节请参考代码作为示例:
没有Instrumentation
的Command
实现能做什么?
运行在目标进程的环境中, 很多JVM
提供的工具方法就可以拿来了:
- 像env, 就是通过
java.lang.System.getenv()
来实现查看目标进程的系统环境变量( 顺便提一下, 我刻意没有实现查看Properities
的功能, 留给大家练手用 :D ) - 还可以利用
java.lang.management.ManagementFactory
获得系统提供的管理Bean, 来实现诸如: 查看线程数, 内存, 执行Full GC
等等
总之, 发挥你的想象力, 指令可以运行在目标进程中了, 还有什么可以直接拿来用的呢?
Instrumentation
若是要用到Instrumentation
的指令, 也同样要继承Command
, 与 env, 但构造器就要多一个Instrumentation
的参数, 如loaded. HouseMD
在实例化指令的时候, 会将Instrumentation
的实例传入.
指令的构造器最多就
Instrumentation
和PrintOut
两个参数, 多了会导致实例化失败.
TransformCommand
要实现一个比trace更牛逼的指令, 前面的方法已经足够让你办到了. 但我还是强烈推荐继承TransformCommand
, 它已经帮你实现了字节码增强的部分(这部分是有很多陷阱的, 除非你有足够的经验, 真的如此我热切的希望你能帮我改进它), 还有常规选项(如-i
,-t
,-l
以及-p
) 剩下你需要做的是:
- 声明参数
- 实现
isCandidate
方法, 以过滤那些需要进行字节码增强的类, - 实现
isDecorating
方法,以过滤那些需要进行字节码增强的类的方法, - 实现
hook
方法, 返回一个回调对象, 它的方法会在特定的时机被调用:enterWith
会在所跟踪的方法进入之前调用,Context
对象有方法上下文的数据exitWith
会在所跟踪的方法退出之后调用,Context
对象有方法上下文的数据heartbeat
会像心跳一样被调用(可能一会快,可能一会慢), 主要用于实时显示信息, 如trace
的调用摘要,now
是当前时间(毫秒)finalize
会在指令结束前调用, 主要用于释放清理资源, 一旦指令运行中出现了异常,Option[Throwable]
会传入它.
细节请参考代码作为示例:
Completer
要想自定义的指令具备良好的交互体验, 那么支持参数自动补全这个功能一定要提供. 实现这点就需要实现Completer
接口的complete
方法, 具体怎么做, 文字不好描述, 还是看源码吧.
不要忘了最后一步
新增的指令需在House中agentOptions
的值(:: Nil
之前)增加一下, 现在方式有点土, 欢迎高手来改进它.
更多相关疑问请提交Issue, 我们一起来讨论:)
完整开发文档请见这里