-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Home
JVM沙箱容器,JVM的非侵入式运行期AOP解决方案
JVM-SANDBOX由纯Java编码完成,基于JVMTI技术规范,为观察和改变代码运行结果提供了即插即用模块接口的容器
在JVM沙箱(以下简称沙箱)的世界观中,任何一次方法的调用都可以分解为BEFORE(进入)、RETURN(返回)和THROWS(异常)三个阶段,由此在三个阶段上引申出对应环节的事件探测和流程控制机制。
// BEFORE
try {
/*
* do something...
*/
// RETURN
return;
} catch (Throwable cause) {
// THROWS
}
基于BEFORE、RETURN和THROWS三个环节事件,可以完成很多类AOP的操作。
- 可以感知和改变方法调用的入参
- 可以感知和改变方法调用返回值和抛出的异常
- 可以改变方法执行的流程
- 在方法体执行之前直接返回自定义结果对象,原有方法代码将不会被执行
- 在方法体返回之前重新构造新的结果对象,甚至可以改变为抛出异常
- 在方法体抛出异常之后重新抛出新的异常,甚至可以改变为正常返回
- 提供了一套能探测事件和改变方法执行流程的API
- 提供了一个即插即用的模块管理容器
- 线上故障定位
- 线上系统流控
- 线上故障模拟
- 方法请求录制和结果回放
- 动态日志打印
- 安全信息监测和脱敏
JVM沙箱还能帮助你做很多很多,取决于你的脑洞有多大了
沙箱提供了即时加载ATTACH和启动加载AGENT两种启动方式,两种方式均能正确完成沙箱启动及其模块的加载。
-
ATTACH方式启动
在不需要重启目标JVM的情况下,无感、动态的完成沙箱容器的启动和方法切面的植入 -
AGENT方式加载
目标JVM启动时完成沙箱容器的启动,并在整个应用启动过程中完成方法切面的植入
-
沙箱容器采用传统的C/S架构模式,通讯协议考虑到可能要部署到内网,需要NAT网关转发,所以采用了HTTP协议。
- HTTP-CLIENT:sandbox.sh
- HTTP-SERVER:沙箱容器(jetty8实现)
-
在对每个目标JVM进程启动沙箱容器时,容器会主动向目标JVM植入一个agent,容器加载的多个module共享这个agent。
沙箱通过自定义的SandboxClassLoader破坏了双亲委派的约定,实现了和观察应用的类隔离。所以不用担心加载沙箱会引起应用的类污染、冲突。
各模块之间类通过ModuleClassLoader实现了各自的独立,达到模块之间、模块和沙箱之间、模块和应用之间互不干扰。
-
隔离
-
沙箱通过自定义的SandboxClassLoader破坏了双亲委派的约定,实现了和观察应用的类隔离。所以不用担心加载沙箱会引起应用的类污染、冲突。
-
沙箱各模块之间类通过ModuleClassLoader实现了各自的独立,达到模块之间、模块和沙箱之间、模块和应用之间互不干扰。
-
-
通讯
- 通过向Bootstrap ClassLoader中注入Spy类,完成观察应用与JVM-Sandbox的通讯
- 沙箱容器会将事件分发给各个Module,完成容器与Module之间的通讯
-
动态插拔
-
字节码编织
-
插入Spy类到字节码中,Spy方法中反射调用JVM-Sandbox的方法。以BeforeEvent为例,进行代码编织展示。
public int add(int a, int b) { try { // 这里开始产生BEFORE事件 Object[] argumentArray = new Object[]{a,b}; Spy.Ret retOnBefore = Spy.onBefore(10001, "com.taobao.test.MyTest", "add", this, argumentArray); // 这里完成参数替换 a = argumentArray[0]; b = argumentArray[1]; // 这里对BEFORE事件的回馈作出响应 if( retOnBefore.state == I_RETURN ) { return (int)retOnBefore.object; } else if( retOnBefore.state == I_THROWS ) { throws (Throwable)retOnBefore.object; } // ------ 到此BEFORE事件产生和处理完成 Object r = sum(a,b); ... }
-
编织完成后,整个代码执行流程将会变成为
-
沙箱一共由三大核心功能组件构成
-
代码编织组件
负责完成预设代码的重写和生效 -
事件处理分发组件
负责完成事件的分发和方法流控控制的执行 -
模块管理组件
负责控制和管理沙箱的各个模块
沙箱的底层提供了一个HTTP-SERVER(Jetty实现),通过HTTP协议完成sandbox.sh和沙箱的控制交互,同时也给各个模块提供了基于HttpServlet和WebSocket规范的API,各模块可以复用沙箱完成各自模块的控制与交互。
JVM沙箱偏向于底层产品,受众面比较窄,问题反馈沟通很可能会因为各种原因造成不及时。所以我们建立了一个钉钉小群,方便大家在这里进行沟通。
JVM沙箱偏向于底层产品,受众面比较窄,问题反馈沟通很可能会因为各种原因造成不及时。所以我们建立了一个钉钉小群,方便大家在这里进行沟通。