java - cglib 代理类中缺少字段注释

标签 java cglib

@Service
public class TestService{

    @DynamicReference
    private ITestProvider testProvider;

    public void run() {

    }
}
DynamicReference dynamicRefrence = filed.getAnnotation(DynamicReference.class);
-->NOT NULL

在这种情况下这段代码没问题。但是当我在方法运行中添加 @Transactional 时,@DynamicReference 将丢失

@Service
public class TestService{

    @DynamicReference
    private ITestProvider testProvider;

    @Transactional
    public void run() {

    }
}
DynamicReference dynamicRefrence = filed.getAnnotation(DynamicReference.class);
-->NULL

如何在cglib代理类中获取字段注释@DynamicReference

这是获取字段代码:

Object o = this.applicationContext.getBean(beanName);
Class<?> clazz = o.getClass();

for (Field filed : clazz.getDeclaredFields()) {
    DynamicReference dynamicRefrence = filed.getAnnotation(DynamicReference.class);
}

最佳答案

来自Class.getDeclaredFields():

Returns an array of Field objects reflecting all the fieldsdeclared by the class or interface represented by this Class object. This includes public, protected, default(package) access, and private fields, but excludes inherited fields.

就您而言,一旦您拥有来自 cglib 的基于子类的代理,该字段将仅存在于父类(super class)中。根据您的用例,您可能希望收集继承链中具有自定义注释的所有字段。

示例代码:

    Collection<Field> fieldsWithAnnotation = new ArrayList<>();

    Class<?> clazz = // your class

    while(clazz != null) {
        for (Field field : clazz.getDeclaredFields()) {
            DynamicReference dynamicRefrence = field.getAnnotation(DynamicReference.class);
            if(dynamicRefrence != null)
                fieldsWithAnnotation.add(field);
        }
        clazz = clazz.getSuperclass();
    }

编辑:这种方法可以找到带注释的字段。但是,执行 field.set(proxyInstance, value) 实际上会在代理中设置字段。这对您没有帮助,因为即使代理子类,它仍然使用委托(delegate)将方法调用转发到实际类的包装实例。由于您的目标显然是在这个包装实例中设置字段,因此我建议您不要使用自定义字段注入(inject),而是使用 setter 注入(inject)。您的代码大致如下(未经测试):

// in TestService
private ITestProvider testProvider;

@DynamicReference
public void setTestProvider(ITestProvider testProvider) { ... }

// Getting the method
while(clazz != null) {
    for (Method method : clazz.getDeclaredMethods()) {
        DynamicReference dynamicRefrence = method.getAnnotation(DynamicReference.class);
        if(dynamicRefrence != null)
            methodsWithAnnotation.add(method);
    }
    clazz = clazz.getSuperclass();
}

// invoking it
method.invoke(proxyInstance, dependencyInstanceYouWantToSet);

代理应该将方法调用委托(delegate)给您的包装实例。也许您甚至想保护该方法。

另一种方法是获取代理的回调字段并在该实例上设置该字段,但上面的方法似乎更干净(有些人可能会说魔法字段注入(inject)是邪恶的,您应该始终使用 setter/constructor 注入(inject)一种干净的 oop 方法)。

编辑 2:如果您想真正重新发明 DI 框架并利用底层现有的 DI 框架功能,也许您也可以重新考虑。我想到了使用 @Qualifier 或一些自定义注入(inject)解析器。参见例如this tutorial

关于java - cglib 代理类中缺少字段注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58832289/

相关文章:

java - 如何在 Eclipse 中更改 Android 的 Java 构建路径?

Java如何使用Hashset在读取文件时添加带句点的字符串

java - 带有 jasper 报告的多个图表

java - 无法为我的 Maven 父项目构建 JAR 文件

java - 关于 Cglib MethodInterceptor 调用方法的困惑

java - 在没有运行时开销的情况下模拟接口(interface)的廉价方法

javascript - Selenium 网络驱动程序 : Can't access element containing onclick and text attributes

Spring CGLib 和 EasyMock - 尝试重复的类定义

maven - Maven 中心的 CGLIB 3

java.lang.NoClassDefFoundError : net/sf/cglib/asm/util/TraceClassVisitor