@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/