当使用例如cglib或javassist proxies创建代理时,该代理是通过创建代理目标的子类来实现的。但是,这意味着此代理上的注释将丢失。当一个类由两个库处理时,这是有问题的,其中:
- 第一个库需要创建给定类的代理才能运行。
- 第二个库通过读取对象的注释来处理对象。
对于第二个库,同时使用第一个库时,注释已消失。问题是:是否存在具有高级 API 的运行时代码生成库,可以轻松保留代理类的注释?
当使用例如cglib或javassist proxies创建代理时,该代理是通过创建代理目标的子类来实现的。但是,这意味着此代理上的注释将丢失。当一个类由两个库处理时,这是有问题的,其中:
对于第二个库,同时使用第一个库时,注释已消失。问题是:是否存在具有高级 API 的运行时代码生成库,可以轻松保留代理类的注释?
Byte Buddy是一个用于运行时生成 Java 类的库。它的功能不仅限于创建代理类,而且代理类的创建是一个明显的用例。
假设我们正在处理以下代码:
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation { }
@MyAnnotation
class Foo {
@MyAnnotation
public void bar() { }
}
然后我们可以在运行时创建一个覆盖该bar
方法的子类。该bar
方法的重写实现被实现为简单地调用其超级实现:
Class<?> runtimeType = new ByteBuddy()
.withAttribute(TypeAttributeAppender.ForSuperType.INSTANCE)
.withDefaultMethodAttributeAppender(MethodAttributeAppender.ForInstrumentedMethod.INSTANCE)
.subclass(Foo.class)
.method(named("bar")).intercept(SuperMethodCall.INSTANCE)
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
使用上面的运行时类,我们现在可以验证结果类型:
assertNotEquals(Foo.class, runtimeType);
assertThat(runtimeType.isAnnotationPresent(MyAnnotation.class)), is(true));
assertThat(runtimeType.getDeclaredMethod("bar").isAnnotationPresent(MyAnnotation.class)), is(true));
MyAnnotation
尽管有子类,但类型和方法都被注释了。通过调用getDeclaredMethod
,我们进一步验证子类实际上定义了一个新方法。
披露:我是 Byte Buddy 的作者,我想为这个问题提供一个答案,这个问题在稍微更具体的上下文中经常在 SO 上被问到。此外,我想借此机会为 Byte Buddy 创建一个 SO 标签。
我的意思是......或者你可以只使用 Javassist 并重置方法的主体,附加方法的末尾,或者附加到方法的开头。或者只是在类中添加一个新方法,并没有真正理解这一点。
假设您的班级有 yourMethodName 方法。我觉得 Foo Bar 并没有帮助人们并导致更多的混乱。因此,我将尝试使用所选方法名称提供更易于理解的内容。这组 Javassist 函数实际上可以在代码中工作。
ClassPool classPool = HookManager.getInstance().getClassPool();
CtClass ctClass = classPool.getCtClass("com.domain.YourClassName");
ctClass.getMethod("yourMethodName", "()V").insertAfter("FunCreator funCreator = new FunCreator.funMethod()");
insertAfter 在方法的末尾, insertBefore 在方法的开头,如果你想重写整个方法而不改变它的调用方式,你也可以使用 setBody。
请注意,这仅适用于启动时的类加载,如果您想在运行时在代理的帮助下更改方法,您可能希望挂接到对该方法的调用,然后发出它。Byte Buddy 有代理,Javassist 没有。Javassist 在大多数情况下表现不佳,但在这种情况下,听起来您要么用错了,要么不知道如何使用它。