`Advice.WithCustomMapping` 绑定一个动态添加的字段
`Advice.WithCustomMapping` to bind a dynamically added field
使用 byte-buddy
,我想我需要使用 Advice.WithCustomMapping
来引用我根据某些运行时逻辑选择的任意字段。
但是,我有点不知道如何创建对作为检测的一部分添加的字段的引用?
AgentBuilder ab = new AgentBuilder.Default();
...
ab = ab.type(named(type))
.transform((builder, td, _cl, _m) ->
builder
.defineField("$lat$", LatencyEvent.class, Visibility.PUBLIC) // new field; I want to create multiple
.visit(Advice.withCustomMapping()
.bind(Lat.class, td.getDeclaredFields().filter(named("$lat$")).getOnly()) // ok, here I want to reference the newly added field
.to(EndLatAdvice.class)
.on(isMethod().and(named(until)))) // pick a target method
...
private static class EndLatAdvice {
@Advice.OnMethodEnter
static void enter(@Lat LatencyEvent l) { // hoping to have access to the newly added field
...
}
此外,当我们这样做时,我注意到对于 Advice.FieldValue
我们需要指定 readOnly = false
,如果我们想写回那个字段。 WithCustomMapping
是如何完成的(假设这是正确的工具)。
好的,我想我想出了两个办法。很高兴听到哪一个可以被认为是“规范的”。
- 创建另一个
AgentBuilder
只创建字段:
AgentBuilder addField = new AgentBuilder.Default();
AgentBuilder ab = new AgentBuilder.Default();
...
addField = addField.type(named(type))
.transform((builder, td, _cl, _m) ->
builder
.defineField("$lat$", LatencyEvent.class, Visibility.PUBLIC))
ab = ab.type(named(type))
.transform((builder, td, _cl, _m) ->
builder
.visit(Advice.withCustomMapping()
.bind(Lat.class, td.getDeclaredFields().filter(named("$lat$")).getOnly()) // ok, this one now finds the field
.to(EndLatAdvice.class)
.on(isMethod().and(named(until)))) // pick a target method
...
addField.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.ignore(none())
.installOn(inst);
ab.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.ignore(none())
.installOn(inst);
现在有两个agent,一个是三个简单的创建字段,第二个重新定义相同的类,等到运行,就可以看到字段了由 addField
创建。不知道执行顺序有没有保证
- 创建
Latent
字段引用而不是按名称查找。
TypeDescription.Generic latField = new TypeDescription.Generic.OfNonGenericType.ForLoadedType(LatencyEvent.class);
...
ab = ab.type(named(type))
.transform((builder, td, _cl, _m) ->
builder
.defineField("$lat$", LatencyEvent.class, Visibility.PUBLIC) // new field; I want to create multiple
.visit(Advice.withCustomMapping()
.bind(Lat.class, new FieldDescription.Latent(td, "$lat$", 1, latField, List.of())) // ok, we can reference the field by name
.to(EndLatAdvice.class)
.on(isMethod().and(named(until)))) // pick a target method
这个只有一个特工。
但这是一个只读引用 - 无法写回该字段。
为了写作,需要参考略有不同:
- 与上面的 (2) 相同,除了
bind
对于 Lat.class
注释应该是:
...
.bind(Lat.class, new Advice.OffsetMapping.ForField.Unresolved.WithImplicitType(latField, false, Assigner.Typing.STATIC, "$lat$"))
...
所以,仍然是 bind
,只需要 ForField...WithImplicitType
而不是 Latent
参考。
您将提供一个 Advice.OffsetMapping
的实例,其中您具有检测类型,其中所有字段都作为参数值提供。
根据该映射,您将 return 此字段的 Advice.OffsetMapping.Target.ForField.ReadWrite
实例,除非您要应用一些自定义内容。
使用 byte-buddy
,我想我需要使用 Advice.WithCustomMapping
来引用我根据某些运行时逻辑选择的任意字段。
但是,我有点不知道如何创建对作为检测的一部分添加的字段的引用?
AgentBuilder ab = new AgentBuilder.Default();
...
ab = ab.type(named(type))
.transform((builder, td, _cl, _m) ->
builder
.defineField("$lat$", LatencyEvent.class, Visibility.PUBLIC) // new field; I want to create multiple
.visit(Advice.withCustomMapping()
.bind(Lat.class, td.getDeclaredFields().filter(named("$lat$")).getOnly()) // ok, here I want to reference the newly added field
.to(EndLatAdvice.class)
.on(isMethod().and(named(until)))) // pick a target method
...
private static class EndLatAdvice {
@Advice.OnMethodEnter
static void enter(@Lat LatencyEvent l) { // hoping to have access to the newly added field
...
}
此外,当我们这样做时,我注意到对于 Advice.FieldValue
我们需要指定 readOnly = false
,如果我们想写回那个字段。 WithCustomMapping
是如何完成的(假设这是正确的工具)。
好的,我想我想出了两个办法。很高兴听到哪一个可以被认为是“规范的”。
- 创建另一个
AgentBuilder
只创建字段:
AgentBuilder addField = new AgentBuilder.Default();
AgentBuilder ab = new AgentBuilder.Default();
...
addField = addField.type(named(type))
.transform((builder, td, _cl, _m) ->
builder
.defineField("$lat$", LatencyEvent.class, Visibility.PUBLIC))
ab = ab.type(named(type))
.transform((builder, td, _cl, _m) ->
builder
.visit(Advice.withCustomMapping()
.bind(Lat.class, td.getDeclaredFields().filter(named("$lat$")).getOnly()) // ok, this one now finds the field
.to(EndLatAdvice.class)
.on(isMethod().and(named(until)))) // pick a target method
...
addField.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.ignore(none())
.installOn(inst);
ab.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.ignore(none())
.installOn(inst);
现在有两个agent,一个是三个简单的创建字段,第二个重新定义相同的类,等到运行,就可以看到字段了由 addField
创建。不知道执行顺序有没有保证
- 创建
Latent
字段引用而不是按名称查找。
TypeDescription.Generic latField = new TypeDescription.Generic.OfNonGenericType.ForLoadedType(LatencyEvent.class);
...
ab = ab.type(named(type))
.transform((builder, td, _cl, _m) ->
builder
.defineField("$lat$", LatencyEvent.class, Visibility.PUBLIC) // new field; I want to create multiple
.visit(Advice.withCustomMapping()
.bind(Lat.class, new FieldDescription.Latent(td, "$lat$", 1, latField, List.of())) // ok, we can reference the field by name
.to(EndLatAdvice.class)
.on(isMethod().and(named(until)))) // pick a target method
这个只有一个特工。
但这是一个只读引用 - 无法写回该字段。
为了写作,需要参考略有不同:
- 与上面的 (2) 相同,除了
bind
对于Lat.class
注释应该是:
...
.bind(Lat.class, new Advice.OffsetMapping.ForField.Unresolved.WithImplicitType(latField, false, Assigner.Typing.STATIC, "$lat$"))
...
所以,仍然是 bind
,只需要 ForField...WithImplicitType
而不是 Latent
参考。
您将提供一个 Advice.OffsetMapping
的实例,其中您具有检测类型,其中所有字段都作为参数值提供。
根据该映射,您将 return 此字段的 Advice.OffsetMapping.Target.ForField.ReadWrite
实例,除非您要应用一些自定义内容。