当我想在集合中保存多个bean时,是否需要在Spring中同步@Autowired方法?

时间:2019-12-17 18:00:04

标签: java spring spring-boot dependency-injection

假设我在基于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可以同时在多个线程中调用此方法吗?还是会依次调用此方法?

谢谢

4 个答案:

答案 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);
  }
}