我有一堆实现类型
Repository<T ? extends Node>
的存储库 bean。现在我可以从用户那里获取随机节点列表,并且我想获取每个节点的适当存储库。从Spring 4.0RC1开始,我们可以像这样自动装配存储库:
@Autowired Repository<SomeNode> someNodeRepository;
如记录此处。
这工作得很好,但我的问题是如何根据泛型类型动态地执行此操作。
我想做的是:
public <T extends Node> T saveNode(T node) {
Repository<T> repository = ctx.getBean(Repository.class, node.getClass());
return repository.save(node);
}
其中第二个参数是泛型类型。 这当然行不通,尽管它可以编译。
我找不到任何相关的/文档。
你可以这样做:
String[] beanNamesForType = ctx.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, node.getClass()));
// If you expect several beans of the same generic type then extract them as you wish. Otherwise, just take the first
Repository<T> repository = (Repository<T>) ctx.getBean(beanNamesForType[0]);
从 Spring 5.1 开始,你可以获得
Repository<T>
类型的 bean,如下所示:
public static <T> Repository<T> getRepositoryFor(Class<T> clazz) {
ResolvableType type = ResolvableType.forClassWithGenerics(Repository.class, clazz);
return (Repository<T>) context.getBeanProvider(type).getObject();
}
如果您可以确定对于
Node
的每个具体子类(例如 SomeNode
),SomeNode
类型的每个对象都将是实际的 SomeNode
而不是子类或代理,那就很容易了。只需对存储库名称使用约定(例如 SomeNodeRepository
),这将是微不足道的:
Repository<T> repository = ctx.getBean(node.getClass().getSimpleName()
+ "Repository", Repository.class);
但是你知道获得子类或代理的风险很高......
所以你可以尝试让每个 Node 子类实现一个
nameForRepo
方法:
class Node {
...
abstract String getNameForRepo();
}
然后在子类中
class SomeNode {
static private final nameForRepo = "SomeNode";
...
String getNameForRepo() {
return nameForRepo;
}
}
这样,即使你获得了代理或子类,你也可以这样做:
public <T extends Node> T saveNode(T node) {
Repository<T> repository = ctx.getBean(node.getNameForRepository()
+ "Repository", Repository.class);
return repository.save(node);
}
或者,该方法可以直接返回存储库名称。
如果我理解得很好,你想获得一个具有 Repository 类和不同泛型类型的 bean 实例吗?
恐怕你没有 Spring 的动态方式,但我有一个解决方案:
你的泛型类型应该是你的类中的一个字段,你的Repository类中必须有一个构造函数来设置你的泛型类型,你的Repository类应该是这样的:
public class Repository<T>{
Class<T> nodeClass;
public Repository(Class<?> clazz){
this.nodeClass = clazz;
}
// your codes...
}
为每个Node声明一个Repository bean,假设你有Repository和Repository,如果你使用xml配置,则需要添加:
<bean id="someNodeRep" class="your.package.Repository">
<constructor-arg>
<value>your.package.SomeNode</value>
</constructor-arg>
</bean>
<bean id="otherNodeRep" class="your.package.Repository">
<constructor-arg>
<value>your.package.OtherNode</value>
</constructor-arg>
</bean>
以这种方式“自动装配”您的存储库:
@Autowired
@Qualifier("someNodeRep")
Repository<SomeNode> someNodeRepository;
@Autowired
@Qualifier("otherNodeRep")
Repository<OtherNode> otherNodeRepository;