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


JVM Sandbox整体架构本章节不详细讲述JVM SandBox的所有架构设计 , 只讲其中几个最重要的特性 。详细的架构设计可以看原框架代码仓库的Wiki 。
类隔离很多框架通过破坏双亲委派(我更愿意称之为直系亲属委派)来实现类隔离 , SandBox也不例外 。它通过自定义的SandboxClassLoader破坏了双亲委派的约定 , 实现了几个隔离特性:

  • 和目标应用的类隔离:不用担心加载沙箱会引起原应用的类污染、冲突 。
  • 模块之间类隔离:做到模块与模块之间、模块和沙箱之间、模块和应用之间互不干扰 。

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

文章插图
无侵入AOP与事件驱动JVM-SANDBOX属于基于Instrumentation的动态编织类的AOP框架 , 通过精心构造了字节码增强逻辑 , 使得沙箱的模块能在不违反JDK约束情况下实现对目标应用方法的无侵入运行时AOP拦截 。
如何把Java代码玩出花?JVM Sandbox入门教程与原理浅谈

文章插图
从上图中 , 可以看到一个方法的整个执行周期都被代码“加强”了 , 能够带来的好处就是你在使用JVM SandBox只需要对于方法的事件进行处理 。
// BEFOREtry {/** do something...*/// RETURNreturn;} catch (Throwable cause) {// THROWS}
在沙箱的世界观中 , 任何一个Java方法的调用都可以分解为BEFORERETURNTHROWS三个环节 , 由此在三个环节上引申出对应环节的事件探测和流程控制机制 。
基于BEFORERETURNTHROWS三个环节事件分离 , 沙箱的模块可以完成很多类AOP的操作 。
  1. 可以感知和改变方法调用的入参
  2. 可以感知和改变方法调用返回值和抛出的异常
  3. 可以改变方法执行的流程
    • 在方法体执行之前直接返回自定义结果对象 , 原有方法代码将不会被执行
    • 在方法体返回之前重新构造新的结果对象 , 甚至可以改变为抛出异常
    • 在方法体抛出异常之后重新抛出新的异常 , 甚至可以改变为正常返回
一切都是事件驱动的 , 这一点你可能很迷糊 , 但是在下文的实战环节中 , 可以帮助你理解 。
JVM Sandbox代码实战我将实战章节提前到这里 , 目的是方便大家快速了解使用JVM SandBox开发是一件多么舒服的事情(相比于自己使用字节码替换等工具) 。
使用版本:JVM-Sandbox 1.2.0
官方源码:https://github.com/alibaba/jvm-sandbox
我们来实现一个小工具 , 在日常工作中 , 我们总会遇到一些巨大的Spring工程 , 里面有茫茫多的Bean和业务代码 , 启动一个工程可能需要5分钟甚至更久 , 严重拖累开发效率 。
我们尝试使用JVM Sandbox来开发一个工具 , 对应用的Spring Bean启动耗时进行一次统计 。这样能一目了然的发现工程启动慢的主要原因 , 避免去盲人摸象的优化 。
最终效果如图:
如何把Java代码玩出花?JVM Sandbox入门教程与原理浅谈

文章插图
图中统计了一个应用从启动开始到所有SpringBean的启动耗时 , 按照从高到低排序 , 我由于是demo应用 , Bean的耗时都偏低(也没有太多业务Bean) , 但在实际应用中会有非常多几秒甚至十几秒才完成初始化的Bean , 可以进行针对性优化 。
在JVMSandBox中如何实现上面的工具?其实非常简单 。

经验总结扩展阅读