JVM动态字节码注入工具-Byteman

Byteman是一个字节码操作工具,它使得在加载时或在应用程序运行时更改Java应用程序的操作变得简单。它无需重写或重新编译原始程序即可工作。实际上,Byteman甚至可以用来修改Java代码,这些代码构成了Java虚拟机的一部分,比如String、Thread等类。Byteman采用了一种基于Java的清晰、简单和易于使用的事件条件动作(ECA)规则语言。ECA规则用于指定应该在何处、何时以及如何转换原始Java代码以修改其操作。

Byteman的发明主要是为了使用一种称为错误注入的技术来支持多线程和多jvm Java应用程序的自动化测试。它包含了一些被设计用来解决这种类型的测试中出现的问题的特性。Byteman在四个主要领域为测试自动化提供了明确的支持:

  • 跟踪特定代码路径的执行并显示应用程序或JVM状态
  • 通过改变状态、进行计划外的方法调用或强制执行意外的返回或抛出来破坏正常执行
  • 编排由独立应用程序线程执行的活动的计时
  • 监控和收集汇总应用程序和JVM操作的统计信息

Byteman下载

安装:

bash 复制代码
vim /etc/profile

export BYTEMAN_HOME=/root/byteman-download-4.0.23/bin

 export PATH=$PATH:$BYTEMAN_HOME/bin

source /etc/profile

启动应用:

bash 复制代码
java -jar  -javaagent:/root/byteman-download-4.0.23/lib/byteman.jar=listener:true,boot:/root/byteman-download-4.0.23/lib/byteman.jar -Dorg.jboss.byteman.transform.all  shushan-server-v2-0.0.1-SNAPSHOT.jar
java 复制代码
package com.kexuexiong.shushan.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import com.kexuexiong.shushan.service.BannerService;
import com.kexuexiong.shushan.entity.Banner;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * <p>
 * 轮播图 前端控制器
 * </p>
 *
 * @author kexuexiong
 * @since 2024-04-22
 */
@Controller
@Slf4j
@RequestMapping("/banner")
public class BannerController {


    @Autowired
    private BannerService bannerService;

    @GetMapping(value = "/")
    public ResponseEntity<Page<Banner>> list(@RequestParam(required = false) Integer current, @RequestParam(required = false) Integer pageSize) {
        log.info("banner list");

        
        if (current == null) {
            current = 1;
        }
        if (pageSize == null) {
            pageSize = 10;
        }
        Page<Banner> aPage = bannerService.page(new Page<>(current, pageSize));
        return new ResponseEntity<>(aPage, HttpStatus.OK);
    }

    @GetMapping(value = "/{id}")
    public ResponseEntity<Banner> getById(@PathVariable("id") String id) {
        return new ResponseEntity<>(bannerService.getById(id), HttpStatus.OK);
    }

    @PostMapping(value = "/create")
    public ResponseEntity<Object> create(@RequestBody Banner params) {
        bannerService.save(params);
        return new ResponseEntity<>("created successfully", HttpStatus.OK);
    }

    @PostMapping(value = "/delete/{id}")
    public ResponseEntity<Object> delete(@PathVariable("id") String id) {
        bannerService.removeById(id);
        return new ResponseEntity<>("deleted successfully", HttpStatus.OK);
    }

    @PostMapping(value = "/update")
    public ResponseEntity<Object> update(@RequestBody Banner params) {
        bannerService.updateById(params);
        return new ResponseEntity<>("updated successfully", HttpStatus.OK);
    }
}

注入规则:

ruleList.btm:

bash 复制代码
RULE trace bananerList entry
CLASS com.kexuexiong.shushan.controller.BannerController
METHOD list
AT ENTRY
IF true
DO throw new RuntimeException("list int")
ENDRULE

RULE trace bananerList exit
CLASS com.kexuexiong.shushan.controller.BannerController
METHOD list
AT EXIT
IF true
DO throw new RuntimeException("list out")
ENDRULE

规则解析:官方文档

bash 复制代码
  ######################################
  # Example Rule Set
  #
  # a single rule definition
  RULE example rule
  # comment line in rule body
  . . .
  ENDRULE

规则是在脚本中定义的,脚本由一系列规则定义和注释行交错组成。注释可以出现在规则定义的正文中,也可以出现在定义之前或之后,但注释必须与规则文本分开。注释是以#字符开头的行:

规则事件规范标识与目标类关联的目标方法中的特定位置。目标方法可以是静态方法,也可以是实例方法或构造函数。如果没有指定详细位置,则默认位置是目标方法的入口。因此,单个规则的基本模式如下:

bash 复制代码
  # rule skeleton
  RULE <rule name>
  CLASS <class name>
  METHOD <method name>
  BIND <bindings>
  IF  <condition>
  DO  <actions>
  ENDRULE

rule关键字后面的规则名称可以是任何自由格式的文本,但限制是它必须包含至少一个非空格字符。规则名称不必是唯一的,但如果它们清楚地标识规则,则在调试规则脚本时显然会有所帮助。每当在解析、类型检查、编译或执行过程中遇到错误时,都会打印规则名称。

class和method关键字后面的类名和方法名必须在同一行。类名可以标识带有或不带有包限定符的类。方法名可以标识有或没有参数列表或返回类型的方法。构造函数方法使用特殊名称标识,类初始化方法使用特殊名称标识。例如,

bash 复制代码
# class and method example
  RULE any commit on any coordinator engine
  CLASS CoordinatorEngine
  METHOD commit
  . . .
  ENDRULE

此规则将仅匹配CoordinatorEngine包中的类 com.arjuna.wst11.messaging.engines,并且仅匹配没有参数且返回类型为 State 的方法提交。请注意,在此示例中,未指定类 State 的包。类型检查器将从省略参数或返回类型的匹配方法中推断出参数或返回类型的包。前面的示例还使用了位置说明符AT LINE。line 关键字后面的文本必须能够被解析以得出整数行号。这会指示代理在源代码中特定行的开头插入触发器调用。注意:

Byteman 代理通常不会转换包中的任何类java.lang,也永远不会转换包中的类org.jboss.byteman,即 byteman 包本身。

可以通过使用(内部格式) 分隔符来指定内部类,以区分内部类与其封闭的外部类 o r g . m y . L i s t 分隔符来指定内部类,以区分内部类与其封闭的外部类org.my.List 分隔符来指定内部类,以区分内部类与其封闭的外部类org.my.ListCons, 例如Map E n t r y Entry EntryWrapper。

其他详细的参考官方文档。

bash 复制代码
# class and method example 2
  RULE commit with no arguments on wst11 coordinator engine
  CLASS com.arjuna.wst11.messaging.engines.CoordinatorEngine
  METHOD State commit()
  AT LINE 324
  . . .
  ENDRULE

注册注入规则:

bash 复制代码
bmsubmit.sh  -l /root/bytemanScript/ruleList.btm

请求访问:

卸载注入:

bash 复制代码
bmsubmit.sh -u /root/bytemanScript/ruleList.btm

卸载后访问:

相关推荐
白总Server9 小时前
JVM解说
网络·jvm·物联网·安全·web安全·架构·数据库架构
向阳12189 小时前
JVM 进阶:深入理解与高级调优
java·jvm
用屁屁笑9 小时前
Java:JVM
java·开发语言·jvm
customer0813 小时前
【开源免费】基于SpringBoot+Vue.JS课程答疑系统(JAVA毕业设计)
java·jvm·vue.js·spring boot·spring cloud·kafka·开源
一叶飘零_sweeeet14 小时前
JVM 中的完整 GC 流程
java·开发语言·jvm
2301_7808538614 小时前
JVM概述
jvm
向阳121815 小时前
JVM入门教程:从概念到实践
java·jvm
不止会JS17 小时前
JVM详解:JVM的系统架构
jvm·系统架构
学点东西吧.1 天前
JVM(一、基础知识)
java·jvm
XMYX-01 天前
JVM 参数配置入门与优化案例
jvm