【alibaba/jvm-sandbox#05】沙箱事件详解

简介: alibaba/jvm-sandbox设计了完善且复杂的沙箱事件,用于实现事件探测和流程控制机制。但不建议对于同一个类、同一个方法多次增强
我是石页兄,朋友不因远而疏,高山不隔友谊情;偶遇美羊羊,我们互相鼓励

欢迎关注微信公众号「架构染色」交流和学习

一、alibaba/jvm-sandbox 概述

alibaba/jvm-sandbox 是 JVM 沙箱容器,一种 JVM 的非侵入式运行期 AOP 解决方案。沙箱容器提供

  1. 动态增强类你所指定的类,获取你想要的参数和行信息甚至改变方法执行
  2. 动态可插拔容器框架

在其能力至上构建的上层应用有:

《【alibaba/jvm-sandbox#02】通过无侵入 AOP 实现行为注入和流控》 介绍了 JVM-SANDBOX 属于基于 Instrumentation 的动态编织类的 AOP 框架,通过精心构造了字节码增强逻辑,使得沙箱的模块能在不违反 JDK 约束情况下实现对目标应用方法的无侵入运行时 AOP 拦截。实现行为注入和流控。

本篇的目标是加深对其沙箱事件机制的理解

二、回顾沙箱事件驱动

在沙箱的世界观中,任何一个Java方法的调用都可以分解为BEFORERETURNTHROWS三个环节,由此在三个环节上引申出对应环节的事件探测和流程控制机制。

// BEFORE
try {

   /*
    * do something...
    */

    // RETURN
    return;

} catch (Throwable cause) {
    // THROWS
}

基于BEFORERETURNTHROWS三个环节事件分离,沙箱的模块可以完成很多类AOP的操作。

  1. 可以感知和改变方法调用的入参
  2. 可以感知和改变方法调用返回值和抛出的异常
  3. 可以改变方法执行的流程

    • 在方法体执行之前直接返回自定义结果对象,原有方法代码将不会被执行
    • 在方法体返回之前重新构造新的结果对象,甚至可以改变为抛出异常
    • 在方法体抛出异常之后重新抛出新的异常,甚至可以改变为正常返回

这个描述看起来很容易理解,但实现以上功能,如此对事件进行描述是不完整的。

三、沙箱事件详解

在JVM-Sandbox的世界观中,任何一个Java方法的调用都可以分解为BEFORERETURNTHROWS三个环节,由此在三个环节上引申出对应环节的事件探测流程控制机制

  • BEFORE事件:执行方法体之前被调用
  • RETURN事件:执行方法体返回之前被调用
  • THROWS事件:执行方法体抛出异常之前被调用

为了记录代码调用行记录,增加了一个LineEvent

  • LINE事件:方法行被执行后调用,目前仅记录行号

CALL事件系列是从GREYS中衍生过来的事件,它描述了一个方法内部,调用其他方法的过程。整个过程可以被描述成为三个阶段

  • CALL_BEFORE事件:一个方法被调用之前
  • CALL_RETURN事件:一个方法被调用正常返回之后
  • CALL_THROWS事件:一个方法被调用抛出异常之后

监听foo方法的BEFORE、RETURN、THROWS、LINE、CALL_BEFORE、CALL_RETURN、CALL_THROWS事件

void foo(){
    // BEFORE-EVENT
    try {

           /*
            * do something...
            */
        try{
            //LINE-EVENT
            //CALL_BEFORE-EVENT
            a();
            //CALL_RETURN-EVENT
        } catch (Throwable cause) {
            // CALL_THROWS-EVENT
        }
        //LiNE-EVENT
        // RETURN-EVENT
        return;

    } catch (Throwable cause) {
        // THROWS-EVENT
    }
}

需要特别注意、注意、注意:IMMEDIATELY_RETURNIMMEDIATELY_THROWS不是事件,他们是流程控制机制,由com.alibaba.jvm.sandbox.api.ProcessControlExceptionthrowReturnImmediately(Object)throwThrowsImmediately(Throwable)触发,完成对方法的流程控制

  • IMMEDIATELY_RETURN:立即调用:RETURN事件
  • IMMEDIATELY_THROWS:立即调用:THROWS事件

整体的流转控制如下图:


                                        +-------+
                                        |       |
 +========+  <return>             +========+    | <return immediately>
 |        |  <return immediately> |        |    |
 | BEFORE |---------------------->| RETURN |<---+
 |        |                       |        |
 +========+                       +========+
     |                              |    ^
     |         <throws immediately> |    |
     |                              |    | <return immediately>
     |                              v    |
     |                            +========+
     |                            |        |
     +--------------------------->| THROWS |<---+
                    <throws>      |        |    |
        <throws immediately>      +========+    | <throws immediately>
                                        |       |
                                        +-------+

四、避免多次增强

Sandbox 支持对于同一个类、同一个方法多次增强,增强之间依然需满足其原定逻辑流转。但官方说不建议多次增强,为什么呢?

下图是两次增强 处理逻辑图如下,每增强一次监听指令的数量指数级增长。

返回状态(0:NONE;1:RETURN;2:THROWS)

  • RET = 1 的时候,这个方法需要立即返回,后面的都不执行了
  • RET = 0 的时候,这个方法继续向下执行
  • RET = 2 的时候,这个方法立即抛出异常

从这个逻辑的复杂度上能直观感受到多次增强后事件以及流控的复杂度是大大的增加了。如果多次松散的增强,遇到非预期结果时,排查效率也很低。所以对同一个类的增强控制,尽量收敛到一个逻辑中,这就要求在使用层面做好设计与规范。

五、最后说一句

我是石页兄,如果这篇文章对您有帮助,或者有所启发的话,欢迎关注笔者的微信公众号【 架构染色 】进行交流和学习。您的支持是我坚持写作最大的动力。

欢迎点击链接扫马儿关注、交流。

相关文章
|
缓存 Java Shell
【alibaba/jvm-sandbox#06】事件监听的关键设计
介绍jvm-sandbox中事件机制的设计,通过用事件Id与事件之间的映射关系进行解耦,通过Spy类的静态方法携带事件Id进行核心事件逻辑的埋点注入
387 0
|
10月前
|
运维 监控 安全
花20天刷完Alibaba JVM笔记去面阿里,却意外拿到京东Offer?
Java虚拟机(Java Virtual Machine 简称JVM)是运行所有Java程序的抽象计算机,是Java语言的运行环境,它是Java 最具吸引力的特性之一。
|
存储 安全 Java
【alibaba/jvm-sandbox#07】事件监听的关键实现
代码中的 new 一个 Listener,sandbox 内部就创建并注册一个与之对应的事件处理器。Spy 的静态方法中将方法事件交给了事件处理器经过一些内部处理,最终回调 listener 的方法。
357 0
|
Java jvm-sandbox 容器
【alibaba/jvm-sandbox#04】通过EventWatchBuilder修改字节码
jvm-sandbox给使用者提供EventWatchBuilder对代码插桩进行了封装;把底层复杂的字节码操控隐藏起来,让使用者仅关注操控什么类、什么方法、方法中的什么逻辑。
279 0
|
Java jvm-sandbox 开发者
【alibaba/jvm-sandbox#03】JavaAgent 修改字节码的机制
开发者一般采用建立一个 Agent 的方式来使用 JVMTI,使用 JVMTI 一个基本的方式就是设置回调函数,在回调函数体内,可以 获取各种各样的VM级信息,甚至控制VM行为,如类加载时修改类
271 0
|
Java jvm-sandbox 容器
【alibaba/jvm-sandbox#02】通过无侵入AOP实现行为注入和流控
任何一个 Java 方法的调用都可以分解为`BEFORE`、`RETURN`和`THROWS`三个环节,由此在三个环节上引申出对应环节的事件探测和流程控制机制。
244 0
|
Java jvm-sandbox Windows
【alibaba/jvm-sandbox#01】debug源码的技巧
alibaba/jvm-sandbox是 一种JVM的非侵入式运行期 AOP 解决方案。沙箱容器提供 1. 动态增强类你所指定的类,获取你想要的参数和行信息甚至改变方法执行 2. 动态可插拔容器框架
349 0
|
4天前
|
存储 缓存 算法
深入浅出JVM(二)之运行时数据区和内存溢出异常
深入浅出JVM(二)之运行时数据区和内存溢出异常
|
13天前
|
存储 Java
深入理解Java虚拟机:JVM内存模型
【4月更文挑战第30天】本文将详细解析Java虚拟机(JVM)的内存模型,包括堆、栈、方法区等部分,并探讨它们在Java程序运行过程中的作用。通过对JVM内存模型的深入理解,可以帮助我们更好地编写高效的Java代码,避免内存溢出等问题。
|
2天前
|
Java Linux Arthas
linux上如何排查JVM内存过高?
linux上如何排查JVM内存过高?
16 0