@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()
:
返回一个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