如何注入(自动装配)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 中,您还可以验证每个组件是否都声明了唯一的非空枚举值。
我了解到在 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 中,您还可以验证每个组件是否都声明了唯一的非空枚举值。