如何把Java代码玩出花?JVM Sandbox入门教程与原理浅谈( 三 )


先贴上思路的整体流程:

如何把Java代码玩出花?JVM Sandbox入门教程与原理浅谈

文章插图
首先新建Maven工程 , 在Maven依赖中引用JVM SandBox , 官方推荐独立工程使用parent方式 。
<parent><groupId>com.alibaba.jvm.sandbox</groupId><artifactId>sandbox-module-starter</artifactId><version>1.2.0</version></parent>新建一个类作为一个JVM SandBox模块 , 如下图:
如何把Java代码玩出花?JVM Sandbox入门教程与原理浅谈

文章插图
使用@Infomation声明mode为AGENT模式 , 一共有两种模式Agent和Attach 。
  • Agent:随着JVM启动一起启动
  • Attach:在已经运行的JVM进程中 , 动态的插入
我们由于是监控JVM启动数据 , 所以需要AGENT模式 。
其次 , 继承com.alibaba.jvm.sandbox.api.Module和com.alibaba.jvm.sandbox.api.ModuleLifecycle 。
其中ModuleLifecycle包含了整个模块的生命周期回调函数 。
  • onLoad:模块加载 , 模块开始加载之前调用!模块加载是模块生命周期的开始 , 在模块生命中期中有且只会调用一次 。这里抛出异常将会是阻止模块被加载的唯一方式 , 如果模块判定加载失败 , 将会释放掉所有预申请的资源 , 模块也不会被沙箱所感知
  • onUnload:模块卸载 , 模块开始卸载之前调用!模块卸载是模块生命周期的结束 , 在模块生命中期中有且只会调用一次 。这里抛出异常将会是阻止模块被卸载的唯一方式 , 如果模块判定卸载失败 , 将不会造成任何资源的提前关闭与释放 , 模块将能继续正常工作
  • onActive:模块被激活后 , 模块所增强的类将会被激活 , 所有com.alibaba.jvm.sandbox.api.listener.EventListener将开始收到对应的事件
  • onFrozen:模块被冻结后 , 模块所持有的所有com.alibaba.jvm.sandbox.api.listener.EventListener将被静默 , 无法收到对应的事件 。需要注意的是 , 模块冻结后虽然不再收到相关事件 , 但沙箱给对应类织入的增强代码仍然还在 。
  • loadCompleted:模块加载完成 , 模块完成加载后调用!模块完成加载是在模块完成所有资源加载、分配之后的回调 , 在模块生命中期中有且只会调用一次 。这里抛出异常不会影响模块被加载成功的结果 。模块加载完成之后 , 所有的基于模块的操作都可以在这个回调中进行
最常用的是loadCompleted , 所以我们重写loadCompleted类 , 在里面开启我们的监控类SpringBeanStartMonitor线程 。
而SpringBeanStartMonitor的核心代码如下图:
如何把Java代码玩出花?JVM Sandbox入门教程与原理浅谈

文章插图
使用Sandbox的doClassFilter过滤出匹配的类 , 这里我们是BeanFactory 。
使用doMethodFilter过滤出要监听的方法 , 这里是initializeBean 。
里取initializeBean作为统计耗时的切入方法 。具体为什么选择该方法 , 涉及到SpringBean的启动生命周期 , 不在本文赘述范围内 。(本文作者:蛮三刀酱)
如何把Java代码玩出花?JVM Sandbox入门教程与原理浅谈

文章插图
接着使用moduleEventWatcher.watch(springBeanFilter, springBeanInitListener, Event.Type.BEFORE, Event.Type.RETURN);
将我们的springBeanInitListener监听器绑定到被观测的方法上 。这样每次initializeBean被调用 , 都会走到我们的监听器逻辑 。
监听器的主要逻辑如下:

经验总结扩展阅读