cglib代理类中的缺少字段注释

问题描述 投票:2回答:1
@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);
}
java cglib
1个回答
2
投票

来自Class.getDeclaredFields()

返回一个Field对象数组,该对象反映由该Class对象表示的类或接口声明的所有字段。这包括公共,受保护的,默认(程序包)访问和私有字段,但不包括继承的字段。

在您的情况下,一旦有了cglib中基于子类的代理,该字段将仅存在于超类中。根据您的用例,您可能希望收集具有自定义批注的继承链中的所有字段。

示例代码:

    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)实际上将在代理中设置该字段。这对您没有帮助,因为即使代理子类仍然使用delegation将方法调用转发到实际类的包装实例。因为您的目标显然是在此包装好的实例中设置字段,所以我建议您不要使用自定义field injection而是使用setter注入。您的代码大致如下所示(未试用):

// 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);

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

替代方法是获取代理的回调字段并在该实例上设置字段,但是上述方法似乎更简洁(有人可能会说魔术字段注入是邪恶的,您应该始终使用setter / constructor注入来干净的方法)。

编辑2:如果您想重新发明DI框架并利用基础现有的DI框架功能,也许您也可以重新考虑。想到使用@Qualifier或某些自定义注入解析器。参见例如this tutorial

© www.soinside.com 2019 - 2024. All rights reserved.