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

Byteman是一个字节码操作工具,它使得在加载时或在应用程序运行时更改Java应用程序的操作变得简单。它无需重写或重新编译原始程序即可工作。实际上,Byteman甚至可以用来修改Java代码,这些代码构成了Java虚拟机的一部分,比如String、Thread等类。Byteman采用了一种基于Java的清晰、简单和易于使用的事件条件动作(ECA)规则语言。ECA规则用于指定应该在何处、何时以及如何转换原始Java代码以修改其操作。
Byteman的发明主要是为了使用一种称为错误注入的技术来支持多线程和多jvm Java应用程序的自动化测试。它包含了一些被设计用来解决这种类型的测试中出现的问题的特性。Byteman在四个主要领域为测试自动化提供了明确的支持:

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

Byteman下载

安装:

vim /etc/profile

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

 export PATH=$PATH:$BYTEMAN_HOME/bin

source /etc/profile

启动应用:

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
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:

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

规则解析:官方文档

  ######################################
  # Example Rule Set
  #
  # a single rule definition
  RULE example rule
  # comment line in rule body
  . . .
  ENDRULE

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

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

  # rule skeleton
  RULE <rule name>
  CLASS <class name>
  METHOD <method name>
  BIND <bindings>
  IF  <condition>
  DO  <actions>
  ENDRULE

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

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

# 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。
其他详细的参考官方文档。

# 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

注册注入规则:

bmsubmit.sh  -l /root/bytemanScript/ruleList.btm

在这里插入图片描述

请求访问:
在这里插入图片描述
在这里插入图片描述

卸载注入:

bmsubmit.sh -u /root/bytemanScript/ruleList.btm

在这里插入图片描述

卸载后访问:
在这里插入图片描述

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

科学熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值