java - 如何装饰现有 Java 对象的方法?
问题描述
编辑:我在https://stackoverflow.com/a/60235242/3236516描述了我们的解决方案
我有一个 java 对象。它是扩展抽象类的许多子类之一的实例。我想修改它的一种方法,以便在调用原始方法之前运行一些额外的代码。我的目标在概念上与 AspectJ 中的切入点相同。
如果我创建原始对象的一些修改版本而不是改变原始对象,那很好。如果解决方案涉及字节码操作,也可以。
前期工作
我考虑过通过 JavaAssist 创建代理。麻烦的是,ProxyFactory 的 create 方法要求我提前知道构造函数的输入类型。我不。我可以在不通过 Objenesis 调用构造函数的情况下创建我的对象,但是生成的代理对象对于构造函数设置的任何值都将具有空值。这意味着只要直接引用构造函数设置的值,我生成的对象的行为就会与原始对象不同。
语境
我们通过 AWS Kinesis Data Analytics 使用 Flink 来转换一些流数据。我们希望在所有StreamOperator 的open() 方法的开头包含一些通用代码,而无需修改每个运算符。一个用例是确保自定义指标代理在操作员运行的每个实例上运行。
解决方案
使用 Byte Buddy,您可以创建一个包装器或一个 Java 代理,它们都可以实现此目标。如果您在调用包装类的构造函数时遇到困难,那么使用 Byte Buddy 也会出现同样的问题,因为任何库都绑定到 JVM 给出的约束。
要创建 Java 代理,请使用AgentBuilder
. 然后,您可以使用该type
步骤指定要拦截的所有类型,例如实现某个接口或扩展类的所有类型。对于transform
,Byte Buddy 提供了一个方法装饰 API 称为Advice
,它允许您添加额外的代码,例如:
class MyAdvice {
@Advice.OnMethodEnter
static void enter() { System.out.println("Hello"); }
}
经过
builder = builder.visit(Advice.to(MyAdvice.class).on(named("foo")));
例如,您可以在您指定的类型的所有名为“foo”的方法的开头打印 hello world。您可以在包的包文档中java.instrument
找到有关 Java 代理的更多信息。
推荐阅读
- php - preg_match_all 的问题:编译失败的括号不匹配
- apache-kafka - 即使在使用 app.spring.cloud.stream.bindings.output.producer.headerMode=raw 之后,也会在 Kafka 0.10 中记录 contentType
- python - 如何在python中使用来自bash的数据流和子进程
- python - 递归神经网络二元分类
- xpath - 试图找到所有没有带有 & 的“修饰符”子节点的节点
- docker - Docker - 从本地网络上的其他机器访问
- excel - 与 Tableau 相比,Tableau 中的数据乘以 18 倍
- jquery - 我怎样才能为孩子制作手风琴检查,以便父母也可以点击?
- python - 如何在应用程序文件夹外调用模板?
- c# - Console.WriteLine 无效条目,因此显示错误