假设我在基于Spring框架的项目中有下一个类:
interface I {
String getName()
}
@Component
class I1 implements I {
@Override
String getName() {return "I1"}
}
@Component
class I2 implements I {
@Override
String getName() {return "I1"}
}
我想使用@Autowired
方法将它们全部收集在地图中:
@Component
public class A {
private Map<I> map = new HashMap<>()
@Autowired
public registerI(I i) {
map.put(i.getName(), i)
}
}
是否应该使该方法registerI
同步?我的意思是,Spring可以同时在多个线程中调用此方法吗?还是会依次调用此方法?
谢谢
答案 0 :(得分:3)
您不必使用synchronized
,因为Spring bean初始化is single-threaded and thread-safe。您可以想到陷阱,例如线程范围的或懒惰的bean,但是对于常规的单例bean,初始化发生在一个线程中。
您可能希望使用synchronized
来确保在调用registerI()
方法之后,您的对象是safely published,尽管带有final
字段的自动装配构造函数更易读
@Component
public class A {
private final Map<String, I> map;
public A(List<I> list) {
map = list.stream().collect(Collectors.toMap(I::getName, i -> i));
}
}
答案 1 :(得分:1)
在应用程序启动期间,您会遇到异常,因为Spring无法确定要注入的接口“ I”的正确实现。您应该使用@Qualifier。
如果您想完成这种情况,那么就足够了。
@Component
public static class A {
private Map<String,I> map = new HashMap<>();
public A(List<I> list) {
//map = list.stream().collect(Collectors.toMap(I::getName, x -> x));
for (I i : list) {
map.put(i.getName(), i);
}
}
}
您将在地图中仅以一个值结束。
如果没有重复的地图键,则注释行将起作用。
答案 2 :(得分:0)
您可以使用@PostConstruct
方法自动关联上下文并从中获取所有感兴趣的bean,并使用它创建一个哈希表。
或
如果您希望该Map在多个类之间共享,请将其设为@Bean
@Configuration
class SomeConfig{
@Autowire Context context;
@Bean(name = "mapBean")
public Map<String, MyCustomClassName1> mapBean() {
Map<String, MyCustomClassName1> map = new HashMap<>();
//populate the map here - from Context
return map;
}
}
答案 3 :(得分:0)
春季由您的咖啡豆填充列表。在postConstruct中创建地图之后
@Component
public class A {
@Autowired
private List<I> list;
@Autowired
private Map<String, I> map;
@PostConstruct
private void init(){
map = list.stream()
.collect(Collectors.toMap(I::getName, element->element);
}
}