@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);
}
答案 0 :(得分: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 将方法调用转发到实际类的包装实例。由于您的目标显然是在此包装好的实例中设置字段,因此建议您不要使用自定义的字段注入,而应使用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