如何注入(自动装配)bean 以在 spring 中使用枚举作为映射键进行映射?

How to inject(autowired) beans to map with enum as map key in spring?

我了解到在 spring 中,我可以通过如下配置的名称 autowire/inject 进入 Map<String, SomeBeanInterface>

public interface DummyInterface{
}

@Component("impl1")
public class Impl1 implement DummyInterface{
}

@Component("impl2")
public class Impl2 implement DummyInterface{
}

public class SomeUsage{
    @Autowired
    private Map<String, DummyInterface> mapping;
    // ...
}

并通过字符串作为键检索 Component,如:

SomeUsage use = new SomeUsage();
DummyInterface dummy = use.getMapping().get("impl1");
// do sth...

但是如果bean mapping的key不是String的类型,而是用户定义的类型Enum,我该如何将bean注入到enumMap中呢?

我已经阅读了一些 post 并了解到它可以通过 xml 文件进行配置。但似乎 xml 配置与 <Enum, Bean> 对紧密耦合,这意味着每次添加新的 <Enum, Bean> 对时,我都必须同步配置文件,和我现在的解决方案相比似乎没有什么区别,即仍然使用 <String, Bean> 集合并在 java 代码中自己维护 <Enum, String> 映射。有没有更好的解决方案来处理这个问题?或者我错过了什么?

您必须添加 @Qualifier("impl1")@Qualifier("impl2")@Autowired 以注入您的实现 class 因为 DummyInterface 有多个实现。

    @Autowired
    @Qualifier("impl2") //Injects impl2 class
    private EnumMap<Your Enum, DummyInterface> mapping;

更多信息EnumMap,可以参考here

您始终必须定义 Enum 和 Spring Bean 之间的映射,但您可以强制要求组件必须声明它们映射到哪个枚举。您可以像这样创建界面:

public interface EnumMappedBean {
    SomeEnum getSomeEnum();
}

然后你要映射的每个组件都必须实现它。

@Component
public class Bean1 implements EnumMappedBean {
    @Override
    public SomeEnum getSomeEnum() {
        return SomeEnum.ENUM1;
    }
}

@Component
public class Bean2 implements EnumMappedBean {
    @Override
    public SomeEnum getSomeEnum() {
        return SomeEnum.ENUM2;
    }
}

然后您可以通过枚举映射每个组件。

@Configuration
public class AppConfig {
    @Bean
    public Map<SomeEnum, EnumMappedBean> getBeansMappedByEnum(@NonNull Collection<EnumMappedBean> enumBeans) {
        return enumBeans.stream()
                .collect(toMap(EnumMappedBean::getSomeEnum, Function.identity()));
    }
}

然后随意注入。

@Service
public class SomeOtherBean {

    private Map<SomeEnum, EnumMappedBean> beansMappedByEnum;

    @Autowired
    public SomeOtherBean(@NonNull Map<SomeEnum, EnumMappedBean> beansMappedByEnum) {
        this.beansMappedByEnum = beansMappedByEnum;
    }
}

在配置 class 中,您还可以验证每个组件是否都声明了唯一的非空枚举值。