spl*_*spl 5 java generics spring spring-boot
我试图找出在 Spring 5 中使用组件的多个副本(通过泛型类型进行区分)的最简洁、最有效的方法。显然我错过了一个概念,因为根据我读到的内容,我觉得这个(下面)应该起作用,但它不起作用,所以我可能误解了泛型类型如何作为限定符工作。
我有这样的安排:
public class Beer {}
Run Code Online (Sandbox Code Playgroud)
public class Coffee {}
Run Code Online (Sandbox Code Playgroud)
@Component
public class Order<T> {
@Autowired
Shop<T> shopToSendOrderTo;
void place(int quantity) {
log.info("Inside the order: " + this);
shopToSendOrderTo.sendOrder(quantity);
}
}
Run Code Online (Sandbox Code Playgroud)
@Component
public class Shop<T> {
void sendOrder(int quantity) {
log.info("Inside the shop: " + this);
}
}
Run Code Online (Sandbox Code Playgroud)
@Configuration
public class Manager implements InitializingBean {
@Autowired
Order<Beer> beerOrder;
@Autowired
Order<Coffee> coffeeOrder;
@Override
public void afterPropertiesSet() {
beerOrder.place(2);
coffeeOrder.place(0);
}
}
Run Code Online (Sandbox Code Playgroud)
然而,当我想要一家商店<啤酒>和一家商店<咖啡>以及一份订单<啤酒>和一份订单<咖啡>时,我最终只创建了一个商店bean和一个订单bean
我可以从执行器/beans 输出中清楚地看到这一点:
"shop":{
"aliases":[
],
"scope":"singleton",
"type":"com.example.generics.Generics.Shop",
"resource":"file [...]",
"dependencies":[
]
},
"order":{
"aliases":[
],
"scope":"singleton",
"type":"com.example.generics.Generics.Order",
"resource":"...",
"dependencies":[
"shop"
]
}
Run Code Online (Sandbox Code Playgroud)
当您打印此引用时,您可以看到每一个都只有一个:
2020-06-15 00:40:05.600 INFO 849 --- [ restartedMain] c.e.g.Generics.Order : Inside the order: com.example.generics.Generics.Order@70792f0a
2020-06-15 00:40:05.602 INFO 849 --- [ restartedMain] c.e.g.Generics.Shop : Inside the shop: com.example.generics.Generics.Shop@41e7f2d5
2020-06-15 00:40:05.602 INFO 849 --- [ restartedMain] c.e.g.Generics.Order : Inside the order: com.example.generics.Generics.Order@70792f0a
2020-06-15 00:40:05.602 INFO 849 --- [ restartedMain] c.e.g.Generics.Shop : Inside the shop: com.example.generics.Generics.Shop@41e7f2d5
Run Code Online (Sandbox Code Playgroud)
重要的是要知道,这@Component
意味着单身人士。这意味着,这种类型的 bean 将仅创建一次,并且在所有位置都将注入相同的实例。
如果这些类没有使用泛型,那么很容易理解您所看到的内容。
但有关泛型参数的信息仅在编译时可用。在运行时它不可用。这就是为什么在运行时Order<Beer>
和 的Order<Coffee>
含义实际上是相同的Order<Object>
。这就是为什么beerOrder
和coffeeOrder
具有相同的值。在执行器中,我们看到有一个类型为 的 bean Order
,这是正确的。这同样适用于Shop<T>
:无论您有多少个引用,它们在运行时的含义都是相同的Shop<Object>
。
不同的解决方案可以得到不同的豆子。
1)使用原型范围
@Component
@Scope("prototype")
public class Order<T> {
...
@Component
@Scope("prototype")
public class Shop<T> {
...
Run Code Online (Sandbox Code Playgroud)
然后在每个注入位置都会创建一个新实例。结果,beerOrder
和coffeeOrder
将是不同的 bean 实例。相应地,每个 的实例Order
将有其自己的 的实例Shop
。
但是:如果您在代码中的某个位置有其他类型的注入 bean Order<Beer>
,则它们中的每个都将是一个单独的实例。你决定,如果这是你想要的。
2)定义单独的类
如果您希望Order<Beer>
在代码中的所有位置注入相同的 bean 实例(单例),并且Order<Coffee>
在所有位置注入相同的 bean 实例(另一个单例),但与 的位置不同Order<Coffee>
,那么可能的解决方案是显式定义相应的类。
因此,您可能想要定义一个具有类型字段的抽象类Shop<T>
。每个Order
类都必须Shop
向父构造函数提供自己的副本。代码可能如下所示:
public abstract class AbstractOrder extends Order<T> {
private Shop<T> shop;
protected AbstractOrder(Shop<T> shop) {
this.shop = shop;
}
@Component
public class BeerOrder extends Order<Beer> {
...
public BeerOrder(BeerShop shop) {
super(shop);
}
@Component
public class CoffeeOrder extends Order<Coffee> {
...
public CoffeeOrder(CoffeeShop shop) {
super(shop);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,Spring 将为每种类型创建一个 bean。在需要的地方,Spring 会将适当的 bean 传递给构造函数。
归档时间: |
|
查看次数: |
1845 次 |
最近记录: |