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

这是get字段代码:

Object o = this.applicationContext.getBean(beanName);
Class<?> clazz = o.getClass();
for (Field filed : clazz.getDeclaredFields()) {
DynamicReference dynamicRefrence = filed.getAnnotation(DynamicReference.class);
}

来自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();
}

EDIT:此方法用于查找带注释的字段。但是,执行field.set(proxyInstance, value)实际上会设置代理中的字段。这对您没有帮助,因为即使代理子类,它仍然使用委派将方法调用转发到实际类的封装实例。由于您的目标显然是在这个封装的实例中设置字段,因此我建议您不要使用自定义字段注入,而是使用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);

代理应该将方法调用委托给封装的实例。也许你甚至想保护这个方法。

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

编辑2:如果你想真正重塑DI框架并利用现有的DI框架功能,也许你也可以重新思考。脑海中浮现的是使用@Qualifier或一些自定义注入解析器。参见本教程

最新更新