我正在JBoss的许多社区中工作,有很多有趣的事情要谈论,以至于我自己无法将自己的每一分都缠住。 这就是为什么我非常感谢有机会不时地欢迎客座博客的主要原因。 今天是Jochen Mader,他是以代码为中心的书呆子群的一部分。 目前,他花费大量的时间编写基于Vert.x的中间件解决方案的代码,为不同的出版物撰写文章并在会议上发表演讲。 他的业余时间属于他的家人,山地车和桌面游戏。 您可以在Twitter @codepitbull上关注他。

有些工具通常是您不希望使用的,但是很高兴在需要时了解它们。 至少对我来说,Byteman属于这一类。 这是我个人的瑞士军刀,用来处理一个大泥巴球或那些可怕的黑森贝格虫之一。 因此,获取当前的Byteman发行版 ,将其解压缩到您计算机上的某个位置,我们可以进行一些繁琐的工作。

它是什么

Byteman是字节码操作和注入工具套件。 它允许我们拦截和替换Java代码的任意部分,以使其表现不同或(故意)破坏它:

  • 将所有线程卡在某个位置,并让它们同时继续(hello race条件)
  • 在意外的位置抛出异常
  • 在执行过程中跟踪代码
  • 更改返回值

还有更多的东西。

一个例子

让我们直接看一些代码来说明Byteman可以为您做些什么。

在这里,我们有一个很棒的Singleton和一个(可悲的)很好的示例代码,您可能在很多地方都可以找到。

public class BrokenSingleton {private static volatile BrokenSingleton instance;private BrokenSingleton() {}public static BrokenSingleton get() {if (instance == null) {instance = new BrokenSingleton();}return instance;}
}

我们假装自己是可怜的人,负责调试一些遗留代码,这些代码显示了生产中的怪异行为。 一段时间后,我们发现了这颗宝石,我们的直觉表明这里有问题。

首先,我们可以尝试如下操作:

public class BrokenSingletonMain {public static void main(String[] args) throws Exception {Thread thread1 = new Thread(new SingletonAccessRunnable());Thread thread2 = new Thread(new SingletonAccessRunnable());thread1.start();thread2.start();thread1.join();thread2.join();}public static class SingletonAccessRunnable implements Runnable {@Overridepublic void run() {System.out.println(BrokenSingleton.get());}}
}

运行此命令,很少有机会看到实际的问题发生。 但是最有可能我们不会看到任何异常情况。 Singleton初始化一次,应用程序按预期执行。 很多时候,人们开始通过增加线程数来进行暴力破解,以期使问题得以解决。 但是我更喜欢一种结构化的方法。

输入Byteman。

DSL

Byteman提供了方便的DSL来修改和跟踪应用程序的行为。 在我的小示例中,我们将从跟踪调用开始。 看一下这段代码。

RULE trace entering
CLASS de.codepitbull.byteman.BrokenSingleton
METHOD get
AT ENTRY
IF true
DO traceln("entered get-Method")
ENDRULERULE trace read stacks
CLASS de.codepitbull.byteman.BrokenSingleton
METHOD get
AFTER READ BrokenSingleton.instance
IF true
DO traceln("READ:\n" + formatStack())
ENDRULE

Byteman脚本的核心构建模块是RULE。

它由几个组件组成(例如从Byteman-Docs中毫不客气地示例:

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

每个规则都必须具有唯一的__规则名称__。 CLASS和METHOD的组合定义了我们希望将修改应用到的位置。 BIND允许我们将变量绑定到可以在IF和DO中使用的名称。 使用IF,我们可以添加触发规则的条件。 在DO中,实际的魔术发生了。

ENDRULE,它结束规则。

知道这一点,我的第一条规则很容易转换为:

当有人调用_de.codepitbull.byteman.BrokenSingleton.get()_时,我想在调用方法主体之前(即__AT ENTRY__转换为)打印字符串“ entered get-Method”。

我的第二条规则可以转换为:

读取(__AFTER READ__)之后,我想查看当前的调用堆栈。

抓取代码并将其放入名为_check.btm_的文件中。 Byteman提供了一个不错的工具来验证您的脚本。 使用__ <bytemanhome> /bin/bmcheck.sh -cp文件夹/包含/已编译/类/至/测试check.btm__来查看脚本是否可以编译。 每次更改它时都要这样做,很容易弄错细节并花很长时间弄清楚它。

现在,脚本已保存并经过测试,现在可以在我们的应用程序中使用它了。

中介

脚本通过代理应用于运行代码。 打开__BrokenSingletonMain-class__的运行配置并添加

__-javaagent:<BYTEMAN_HOME>/lib/byteman.jar=script:check.btm__

到您的JVM参数。 这将注册代理并告诉它运行_check.btm_。

而当我们在这里时,还有更多选择:

如果您需要操纵一些核心Java东西,请使用

__-javaagent:<BYTEMAN_HOME>/lib/byteman.jar=script:appmain.btm,boot:<BYTEMAN_HOME>/lib/byteman.jar__

这会将Byteman添加到引导类路径中,并允许我们操纵_Thread _,_ String_之类的类……我的意思是,如果您想处理如此讨厌的事情……

也可以将代理附加到正在运行的进程。 我们__jps__查找您要附加并运行的进程ID

__<bytemanhome>/bin/bminstall.sh <pid>__

安装代理。 之后运行

__<bytemanhome>/bin/bmsubmit.sh check.btm__

回到我们眼前的问题。

使用修改后的run-Configuration运行我们的应用程序,应导致类似以下的输出

entered get-Method
entered get-Method
READ:
Stack trace for thread Thread-0
de.codepitbull.byteman.BrokenSingleton.get(BrokenSingleton.java:14)
de.codepitbull.byteman.BrokenSingletonMain$SingletonAccessRunnable.run(BrokenSingletonMain.java:20)
java.lang.Thread.run(Thread.java:745)READ:
Stack trace for thread Thread-1
de.codepitbull.byteman.BrokenSingleton.get(BrokenSingleton.java:14)
de.codepitbull.byteman.BrokenSingletonMain$SingletonAccessRunnable.run(BrokenSingletonMain.java:20)
java.lang.Thread.run(Thread.java:745)

恭喜,您刚刚操作了字节码。 输出还不是很有帮助,但这是我们要更改的东西。

线程混乱

现在,随着我们的基础架构的建立,我们可以开始更深入地挖掘。 我们非常确定我们的问题与某些多线程问题有关。 为了检验我们的假设,我们必须同时将多个线程放入关键部分。 使用纯Java,这几乎是不可能的,至少在不对我们要调试的代码进行大量修改的情况下。

使用Byteman可以轻松实现。

RULE define rendezvous
CLASS de.codepitbull.byteman.BrokenSingleton
METHOD get
AT ENTRY
IF NOT isRendezvous("rendezvous", 2)
DO createRendezvous("rendezvous", 2, true);
traceln("rendezvous created");
ENDRULE

该规则定义了一个所谓的集合点。 它允许我们指定多个线程必须到达的位置,直到允许它们继续前进(也称为aa障碍)。

这是规则的翻译:

调用_BrokenSingleton.get()_时,创建一个新的集合点,当2个线程到达时将允许进度。 使集合点可重用,并仅在它不存在时才创建它(IF NOT部分至关重要),否则,我们将在每次对_BrokenSingleton.get()_的调用上创建一个障碍。

定义此障碍后,我们仍然需要显式使用它。

RULE catch threads
CLASS de.codepitbull.byteman.BrokenSingleton
METHOD get
AFTER READ BrokenSingleton.instance
IF isRendezvous("rendezvous", 2)
DO rendezvous("rendezvous");
ENDRULE

翻译:读取_BrokenSingleton.get()_中的_instance_-member之后,在集合点等待,直到第二个线程到达并继续。

在实例空检查之后,我们现在停止来自同一花边中_BrokenSingletonMain_的两个线程。 这就是使比赛条件可再现的方法。 两个线程将继续认为_instance_为null,从而导致构造函数触发两次。

我将这个问题的解决方案留给您……

单元测试

我在撰写此博客文章时发现,有可能在我的单元测试中运行Byteman脚本。 它们的JUNit和TestNG集成很容易集成。

将以下依赖项添加到_pom.xml_

<dependency><groupId>org.jboss.byteman</groupId>   <artifactId>byteman-submit</artifactId><scope>test</scope><version>${byteman.version}</version>
</dependency>

现在,Byteman脚本可以在您的单元测试中执行,如下所示:

@RunWith(BMUnitRunner.class)
public class BrokenSingletonTest
{@Test@BMScript("check.btm")public void testForRaceCondition() {...}
}

将此类测试添加到您的西装中会大大提高Byteman的有用性。 没有更好的方法来防止其他人将这些脚本作为构建过程的一部分来重复您的错误。

结束语

博客文章中只有这么多空间,我也不想开始重写他们的文档。 写这篇文章是一件很有趣的事情,因为我已经有一段时间没有使用Byteman了。 我不知道我如何忽略了单元测试的集成。 这将使我将来更多地使用它。

现在,我建议浏览他们的文档并开始进行注入,有很多事情要做。

翻译自: https://www.javacodegeeks.com/2015/02/byteman-swiss-army-knife-byte-code-manipulation.html

Byteman –用于字节码操纵的瑞士军刀相关推荐

  1. byteman_Byteman –用于字节码操纵的瑞士军刀

    byteman 我正在与JBoss中的许多社区一起工作,有很多有趣的事情要谈论,以至于我无法将自己的每一分都缠住. 这就是为什么我非常感谢有机会不时地欢迎客座博客的主要原因. 今天是Jochen Ma ...

  2. Android AOP之字节码插桩

    背景   本篇文章基于<网易乐得无埋点数据收集SDK>总结而成,关于网易乐得无埋点数据采集SDK的功能介绍以及技术总结后续会有文章进行阐述,本篇单讲SDK中用到的Android端AOP的实 ...

  3. JVM插桩之一:JVM字节码增强技术介绍及入门示例

    字节码增强技术:AOP技术其实就是字节码增强技术,JVM提供的动态代理追根究底也是字节码增强技术. 目的:在Java字节码生成之后,对其进行修改,增强其功能,这种方式相当于对应用程序的二进制文件进行修 ...

  4. 手写 Class 字节码解析技术(一)

    上章节写到关于 java热部署功能的技术点,简单的阐述了关于类加载的问题,既然了解到了class这个知识点了,那就不能不刨根问底的对class解析一番.看看能不能完成一个类似于ASM.Javassis ...

  5. 【字节码插桩】Android 打包流程 | Android 中的字节码操作方式 | AOP 面向切面编程 | APT 编译时技术

    文章目录 一.Android 中的 Java 源码打包流程 1.Java 源码打包流程 2.字符串常量池 二.Android 中的字节码操作方式 一.Android 中的 Java 源码打包流程 Ja ...

  6. python字节码大全

    ddis --- Python 字节码反汇编器 Source code: Lib/dis.py dis 模块通过反汇编支持CPython的 bytecode 分析.该模块作为输入的 CPython 字 ...

  7. CGLIB依赖ASM(关于java字节码框架ASM的学习)

    本文转自: http://www.cnblogs.com/liuling/archive/2013/05/25/asm.html 一.什么是ASM ASM是一个java字节码操纵框架,它能被用来动态生 ...

  8. 看完这一篇,你也可以自如地掌握字节码插桩

    /   今日科技快讯   / 近日,一些国家的黑客频繁对俄罗斯发动网络攻击,以阻止它们正常运行.未来几天,俄罗斯可能与全球互联网断开.针对网络威胁,俄罗斯政府准备启动自己的"大局域网&quo ...

  9. 调研字节码插桩技术,用于系统监控设计和实现

    作者:小傅哥 博客:https://bugstack.cn ❝ 沉淀.分享.成长,让自己和他人都能有所收获!???? ❞ 目录 一.来自深夜的电话! 二.准备工作 三.使用 AOP 做个切面监控 1. ...

最新文章

  1. 学习笔记 九: DNS
  2. time时间格式输出转换
  3. caffe学习笔记25-过拟合原因及分析
  4. 【Java】BIO、NIO、AIO网络编程模型概述
  5. 腾讯开源视频动作检测算法DBG,打破两项世界纪录!
  6. 中文乱码java_JAVA中文乱码问题应该怎么解决?
  7. 香港年轻人买房压力有多大
  8. 毕业论文的6中降重方法
  9. 发票验证出现服务器证书出错,网上认证发票平台证书密码出现错误怎么办?
  10. Vue之使用Coreui框架实现table中的checkbox多选功能
  11. Java图形用户界面
  12. Maven 中的cannot Resolve情况
  13. USGS 官方批量下载软件bda 安装问题
  14. Activity的基本理解
  15. 阿里云智能编码插件,更 Cosy 的开发体验
  16. 我在美团Android研发岗工作的那5年,终局之战
  17. 数字孪生--技术介绍
  18. [程序员学英语]26个英文字母
  19. html怎么打入文本框,html怎么在文本框里面输入文字
  20. Exynos_4412——RTC实验

热门文章

  1. Hibernate基本概念 (4)
  2. 2015蓝桥杯省赛---java---C---9(打印大X)
  3. java的BASE64Encoder,BASE64Decoder加密与解密
  4. 面试官角度的JVM面试
  5. 电脑任务栏跑到右边去了_电脑没有声音怎么解决 电脑没有声音解决方法【详解】...
  6. 命令行执行Junit测试
  7. 使用MRUnit,Mockito和PowerMock进行Hadoop MapReduce作业的单元测试
  8. What are definitions of ​Model, Inference and Algorithm and its associations ?
  9. Servlet请求和响应总结
  10. java中的lombok_如何在Java中使用Lombok删除样板设置器吸气剂