Byteman –用于字节码操纵的瑞士军刀

我正在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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360511.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最短路径问题matlab作图,[MATLAB基础] matlab最短路径的输出问题,用了递归,但程序出错了,请大虾指点...

matlab最短路径的输出问题,用了递归,但程序出错了,请大虾指点 程序如下function shortestpath(w,p,q)c->;l;f;tsize(w);mt(1,1);azeros(m,m);vw;for k1:mfor i1:mfor j1:mb[w(i,j),w(i,k)w(k,j)];w(i,j)min(b);if w(i,j)~v(i,j)a(i,j)k;%a(i,j)10*a(i,j)k;vw;endendendendw;…

快速浏览JAX-RS请求与方法匹配

在本文中&#xff0c;我们来看一下JAX-RS中与资源方法匹配的HTTP请求 。 它是JAX-RS的最基本功能之一。 通常&#xff0c;使用JAX-RS API的开发人员不会接触&#xff08;或真正不需要知道&#xff09; 匹配过程的细节&#xff0c;请放心&#xff0c;由于我们的RESTful&#xff…

$stat php,php stat函数怎么用

php stat函数用于返回关于文件的信息&#xff0c;其语法是fstat(file)&#xff0c;参数file必需&#xff0c;指规定要检查的文件。php stat函数怎么用&#xff1f;定义和用法stat() 函数返回关于文件的信息。语法fstat(file)参数file必需。规定要检查的文件。说明获取由 file 指…

在Java中调用祖父母方法:您不能

在文章保护的重点中&#xff0c;我详细介绍了“受保护”如何扩展“包私有”访问。 我在那儿写道&#xff1a; 你能做的是 覆盖子类中的方法或 使用关键字super调用parent方法。 通常&#xff0c;这实际上是您可以使用受保护的方法完成的所有操作。 &#xff08;请注意&…

Handler(2)

andriod提供了Handler 和 Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。1)Looper: 一个线程可以产生一个Looper对象&#xff0c;由它来管理此线程里的MessageQueue(消息队列)。 2)Handler: 你可以构造Han…

OSGi服务测试助手:ServiceCollector

OSGi服务对于基于松耦合组件的系统开发非常有用。 但是&#xff0c;松散的耦合可能使得难以识别与悬挂服务引用有关的问题。 因此&#xff0c;我们通常运行集成测试以确保运行时服务组件的可用性。 为了减少此类测试所需的样板&#xff0c;我编写了一个简单的实用程序类来获取…

搭建struts2框架

struts是一个经典的MVC模式拦截器比过滤器拦截的力度更大 搭建struts2框架1.引入lib包 9个(2.3版本的)common-fileupload;common-io;common-lang3;common-logging;freemaker;javassistGA;ognl;struts2-core;xwork-core; 2. struts2.xml3. web.xml将所有的跳转都交给struts2处…

adams与matlab联合仿真天线,雷达天线模型MATLAB与ADAMS联合仿真 实验.doc

雷达天线模型MATLAB与ADAMS联合仿真 实验雷达天线模型MATLAB与ADAMS联合仿真实验1.导入雷达天线机械系统模型启动ADAMS&#xff0c;弹出如图1所示的对话框&#xff0c;选择“Open an existing database”,打开保存雷达天线模型的文件夹X:\antenna_test(注&#xff1a;X表示盘符…

【ACM】nyoj_139_我排第几个_201308062046

我排第几个时间限制&#xff1a;1000 ms | 内存限制&#xff1a;65535 KB 难度&#xff1a;3描述 现在有"abcdefghijkl”12个字符&#xff0c;将其所有的排列中按字典序排列&#xff0c;给出任意一种排列&#xff0c;说出这个排列在所有的排列中是第几小的&#xff1f; …

Apache Cassandra和低延迟应用程序

介绍 多年来&#xff0c; Grid Dynamics拥有许多与NoSQL相关的项目&#xff0c;尤其是Apache Cassandra。 在这篇文章中&#xff0c;我们要讨论一个给我们带来挑战的项目&#xff0c;而我们在该项目中试图回答的问题今天也仍然适用。 数字营销和在线广告在2012年很受欢迎&…

php换设备登录逻辑,登录和退出登录的操作逻辑

登录功能的操作逻辑步骤如下&#xff1a;可以分为五个步骤来实现。1、进入页面先判断用户是否已经登录private void isLogin() {//查看本地是否有用户的登录信息SharedPreferences sp this.getActivity().getSharedPreferences("user_info", Context.MODE_PRIVATE);…

Visual studio代码行数统计

Visual studio代码行数统计 Visual Studio中的搜索功能支持正则表达式&#xff08;虽然语法比较诡异&#xff09;&#xff0c;我们完全可以通过正则表达式来遍历整个解决方案从而获得代码行数。 ^:b*[^:b#/].*$ 需要注意&#xff1a;#开头和/开头或者空行都不计入代码量。 如…

在JAX-RS中处理异步请求中的超时

JAX-RS 2.0在客户端和服务器端都支持异步编程范例。 这篇文章重点介绍了使用JAX-RS&#xff08;2.0&#xff09;API在服务器端执行异步REST请求时的超时功能 无需过多介绍&#xff0c;这里是一个快速概述。 为了以异步方式执行方法&#xff0c;您只需 需要指定AsyncResponse接…

strspn php,php返回在字符串中包含 charlist 参数中指定的字符数目的函数strspn()

实例返回在字符串 "Hello world!" 中包含字符 "kHlleo" 的数目&#xff1a;<?php echo strspn("Hello world!","kHlleo");?>定义和用法strspn() 函数返回在字符串中包含 charlist 参数中指定的字符数目。提示&#xff1a;请使…

Java十大简单性能优化

关于“ web scale ”这个流行词有很多炒作&#xff0c;人们花了很多时间来重新组织他们的应用程序体系结构&#xff0c;以使其系统“规模化”。 但是什么是扩展&#xff0c;我们如何确保可以扩展&#xff1f; 缩放的不同方面 上面提到的炒作主要是关于扩展负载 &#xff0c;即…

C#_获取汉字拼音

using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; namespace Ctr.Common.Tools {/// <summary>/// 汉字转拼音静态类,包括功能全拼和缩写&#xff0c;方法全部是静态的/// </summary>public static cla…

php在苹果手机上传不了图片大小,ThinkPHP后台上传图片无默认尺寸解决方法

原标题&#xff1a;ThinkPHP后台上传图片无默认尺寸解决方法随着网站移动端的日益普及&#xff0c;对后台数据的兼容性要求也越来越高。后台数据涵盖范围不断扩大的同时&#xff0c;使得程序处理能力也必须逐步提高。使用ThinkPHP进行长沙网站开发时&#xff0c;后台kindeditor…

幂等与时间解耦之旅

HTTP中的幂等性意味着相同的请求可以执行多次&#xff0c;并且效果与仅执行一次一样。 如果用新资源替换某个资源的当前状态&#xff0c;则无论您执行多少次&#xff0c;最终状态都将与您仅执行一次相同。 举一个更具体的例子&#xff1a;删除用户是幂等的&#xff0c;因为无论…

开发者最容易犯的13个JavaScript错误

开发者最容易犯的JavaScript错误&#xff0c;总结出13个。这些当中可能少不了你犯的错误。我们描述了这些陋习&#xff0c;并列出来解决办法&#xff0c;希望对开发者有帮助。 1.for...数组迭代的用法 Usage of for..in to iterate Arrays 举例&#xff1a; var myArray [ “a…

php h2,微信连接失败:一直返回h2Moved/h2 (终于搞定了)

这几天都OK的&#xff0c;可以正常访问&#xff0c;统计数据上只出现过一次访问失败&#xff0c;但是平均耗时增加了30%估计是上次那个心脏滴血事件后&#xff0c;腾讯要求停用SSLv3&#xff0c;必须用TLSv1&#xff0c;但是之前一直没有停止SSLv3的支持&#xff0c;现在真停了…