- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个无法修改的大型第 3 方代码库,但我需要在许多不同的地方进行微小但重要的更改。我希望使用基于 ByteBuddy 的代理,但我不知道如何使用。我需要替换的调用的形式为:
SomeSystemClass.someMethod("foo")
我需要将其替换为
SomeSystemClass.someMethod("bar")
同时保持对同一方法的所有其他调用不变
SomeSystemClass.someMethod("ignore me")
由于 SomeSystemClass
是一个 JDK 类,因此我不想建议它,而只是建议包含对其调用的类。如何做到这一点?
请注意:
someMethod
是静态的并且最佳答案
Byte Buddy 有两种方法可以实现此目的:
您使用相关调用站点转换所有类:
new AgentBuilder.Default()
.type(nameStartsWith("my.lib.pkg."))
.transform((builder, type, loader, module) -> builder.visit(MemberSubstitution.relaxed()
.method(SomeSystemClass.class.getMethod("someMethod", String.class))
.replaceWith(MyAlternativeDispatcher.class.getMethod("substitution", String.class)
.on(any()))
.installOn(...);
在这种情况下,我建议您在类路径中实现一个类 MyAlternativeDispatcher
(它也可以作为代理的一部分提供,除非您有更复杂的类加载器设置,例如 OSGi,其中您实现条件逻辑:
public class MyAlternativeDispatcher {
public static void substitution(String argument) {
if ("foo".equals(argument)) {
argument = "bar";
}
SomeSystemClass.someMethod(argument);
}
}
这样做,您可以设置断点并实现任何复杂的逻辑,而无需在设置代理后考虑太多字节代码。您甚至可以按照建议独立于代理发送替代方法。
检测系统类本身并使其对调用者敏感:
new AgentBuilder.Default()
.with(RedefinitionStrategy.RETRANSFORMATION)
.disableClassFormatChanges()
.type(is(SomeSystemClass.class))
.transform((builder, type, loader, module) -> builder.visit(Advice.to(MyAdvice.class).on(named("someMethod").and(takesArguments(String.class)))))
.installOn(...);
在这种情况下,您需要反射(reflection)调用者类,以确保您只更改要应用此更改的类的行为。这在 JDK 中并不罕见,并且由于 Advice
将建议类的代码内联(“复制粘贴”)到系统类中,因此您可以不受限制地使用 JDK 内部 API(Java 8 及更早版本)如果您无法使用 stack walker API(Java 9 及更高版本):
class MyAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.Argument(0) String argument) {
Class<?> caller = sun.reflect.Reflection.getCallerClass(1); // or stack walker
if (caller.getName().startsWith("my.lib.pkg.") && "foo".equals(argument)) {
argument = "bar";
}
}
}
您应该选择哪种方法?
第一种方法可能更可靠,但成本相当高,因为您必须处理包或子包中的所有类。如果这个包中有很多类,您将付出相当大的代价来处理所有这些类以检查相关的调用站点,从而延迟应用程序启动。一旦加载了所有类,您就已经付出了代价,并且一切都已就位,而无需更改系统类。然而,您确实需要处理类加载器,以确保您的替换方法对每个人都可见。在最简单的情况下,您可以使用 Instrumentation
API 将包含此类的 jar 附加到引导加载程序,使其全局可见。
使用第二种方法,您只需要(重新)转换单个方法。这样做的成本非常低,但每次调用该方法都会增加(最小的)开销。因此,如果在关键执行路径上多次调用此方法,并且 JIT 没有发现避免它的优化模式,那么您将为每次调用付出代价。在大多数情况下,我更喜欢这种方法,我认为,单个转换通常更可靠和更高效。
作为第三个选项,您还可以使用 MemberSubstitution
并添加您自己的字节代码作为替换(Byte Buddy 在 replaceWith
步骤中公开 ASM,您可以在其中定义自定义字节代码而不是委托(delegate))。这样,您就可以避免添加替换方法的需要,而只需就地添加替换代码。然而,这确实对您提出了严格的要求:
如果您添加条件语句并且 Byte Buddy(或任何人)无法在方法中对其进行优化,则需要后者。堆栈映射帧重新计算非常昂贵,经常失败,并且可能需要类加载锁来死锁。 Byte Buddy 优化了 ASM 的默认重新计算,试图通过避免类加载来避免死锁,但也不能保证,所以你应该记住这一点。
关于java - ByteBuddy 代理将一个方法参数替换为另一个方法参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61148740/
我有一个无法修改的大型第 3 方代码库,但我需要在许多不同的地方进行微小但重要的更改。我希望使用基于 ByteBuddy 的代理,但我不知道如何使用。我需要替换的调用的形式为: SomeSystemC
我正在尝试在 bytebuddy 中创建一个抽象类的子类,并想用我自己的函数覆盖构造函数。我不能让它与 defineConstructor 一起工作。 父类(super class): public
如何将 byte-buddy 生成的类与“org.reflections”一起使用? 例子: Class dynamicType = new ByteBuddy() .
我正在尝试更改已加载类的方法的返回值。 从 ByteBuddy 的文档 (http://bytebuddy.net/#/tutorial) 看来,只要我不添加任何字段/方法,这似乎可以使用 Java
我正在尝试使用 ByteBuddy 附加到我的计算机上运行的正在运行的进程。我希望在附加到正在运行的程序时,我的代理将导致重新加载已加载的类并显示我的 Transformer 的打印语句。 相反,当我
我正在尝试使用 ByteBuddy 重新定义 2 个方法,如下所示: ClassLoader classLoader = ClassLoader.getSystemClassLoader(); Cla
如何使用 AgentBuilder 将子类与名称匹配? 我可以轻松匹配类型本身 new AgentBuilder.Default() .type(named("SomeClass"))
我正在尝试与字节伙伴一起模仿模拟创建。是否可以一次性拦截所有方法? 我尝试了以下方法: new ByteBuddy() .subclass(Object.class) .method(na
我正在尝试编写一个如下所示的通用方法: private static Class immutableVersionOfClass(Class clazz) { return new Byte
我有一个带有方法 m() 的类 A 和带有方法 n() 的类 B。在 A 中,我有一个 B 类型的字段 b。在 m() 中的某个时刻会调用 b.n()。我需要使用 ByteBuddy 更改 A 的代码
我有一堆在普通 JDK 上运行的 Web 服务,我需要拦截所有公共(public)方法才能执行某些操作。一些方法使用@WebParam 注释。使用 ByteBuddy 对 WebService 进行子
如果我有以下内容: public abstract class Parameterized { protected abstract String foo(); } 是否可以这样做: Dynami
语境 我正在使用 ByteBuddy 实现字节码转换,操作过程是一个多步骤过程。 因此,操作必须能够: 扩充原有方法 完全创建新方法 扩充通过 2 引入的方法。 对于 1. 我使用了 @OnMetho
我目前正在尝试制作一个记录器代理,我目前正在拦截 PrepareStatement 类。在 PrepareStatement 中,有多种我希望跟踪的方法,但我感觉我做错了。 通常我现在所做的是拦截我希
我已经使用 ByteBuddy 库有一段时间了,但我发现自己陷入了困境。当测试的类位于同一个文件中(作为静态内部类)时,我可以使用此方法,但现在我已将逻辑分离到一个单独的文件中,它不再起作用。 如果有
如何定义一个方法,然后用 ByteBuddy 装饰它(多次)?这是我的例子 Builder builder = new ByteBuddy().subclass(Object.class).name(
有没有办法使用 ByteBuddy 为没有空构造函数的类创建代理? 这个想法是为给定的具体类型创建一个代理,然后将所有方法重定向到处理程序。 此测试展示了为没有空构造函数的类创建代理的场景,它会抛出
我正在尝试使用 bytebuddy 为进程附加代理。我发现我们可以使用 ByteBuddyAgent.attach(file,"18467");为了这。但是当我尝试执行此操作时,发生了以下错误。 这是
我正在尝试开发一个需要使用注释的工具。一个重要的功能是定位带有注释的元素并更改其值,即 // from this @Annotation(value = "foo") class SomeClass
我正在使用 Byte Buddy 1.9.0 作为基于 Xtext 的编程语言的代码生成器,并且我正在努力为实例化“匿名”类的方法生成字节码。出于所有意图和目的,我试图让 Byte Buddy 创建一
我是一名优秀的程序员,十分优秀!