是否可以使用枚举键注入地图?

时间:2020-07-06 08:11:32

标签: spring-boot kotlin dependency-injection

this问题开始,是否可以向地图注入枚举?

例如,我有枚举:

class enum SomeEnum (val value) {
  ONE("one"),
  TWO("two"),
  THREE("three")
}

我与实现有一些接口:

interface SomeInterface {
}

@Component
@Qualifier("one")
class OneClass: SomeInterface {
...
}

@Component
@Qualifier("two")
class TwoClass: SomeInterface {
...
}

@Component
@Qualifier("three")
class ThreeClass: SomeInterface {
...
}

但是这种注入无效:

@Component
@ConfigurationProperties
class SomeProperties {
   @Autowired
   lateinit var someMap: Map<SomeEnum, SomeInterface>
}

我要自动注入someMap。我该如何解决它,以便在Spring框架方面制作此类代码?

var someMap: Map<SomeEnum, SomeInterface> = Map.of(ONE, oneClass,
                                                   TWO, twoClass,
                                                   THREE, threeClass)

// Where oneClass, twoClass, threeClass - beans instances

2 个答案:

答案 0 :(得分:1)

不太确定要做什么,但是从我的角度来看,您不需要此映射。我假设您想知道在某些情况下使用哪种实现。因此,只需自动连接一个列表或一组接口并对其进行遍历,以找到正确的实现。 (我用Java展示了这些东西)

@Autowired
List<SomeInterface> someInterfaces;

在此列表中,您将拥有此接口的所有注入的实现。如果仍然需要一个Enum来查看要使用的实现,只需将此作为属性添加到每个实现类中。因此,您可以通过其实现获取Enum值。

编辑: 创建一个配置类并自动连接实现列表。在此配置类中,您将创建地图的Bean。

@Configuration
public class MyMapConfig {

    @Autowired
    List<SomeInterface> someInterfaces;

    @Bean
    public Map<SomeEnum, SomeInterface> myMap() {
        Map<SomeEnum, SomeInterface> map = new HashMap<>();
        someInterfaces.forEach(s -> {
            // logic here to add correct Enum to its implementation.
            map.put(SomeEnum.A, s);
        });
        return map;

    }

    public enum SomeEnum {
        A, B, C
    }
}

然后,您可以将地图自动连线到所需的任何位置:

@Autowired
Map<SomeEnum, SomeInterface> myMap;

答案 1 :(得分:1)

  1. 首先,您滥用@Qualifier注释。它不是要命名bean,而是要帮助Spring在多个中选择单个自动装配候选。 @Qualifier仅在注入点有意义-与@Autowired配对可用于类属性
@Autowired
@Qualifier("one")
lateinit var someImpl: SomeInterface

或用于注入方法/构造函数参数

@Bean
fun createSomeService(@Qualifier("two") someImpl: SomeInterface): SomeService {
   return SomeService(someImpl)
}

//or

class SomeService(@Qualifier("three") private val someImpl: SomeInterface) { 
    ... 
}

正确命名Bean的方法就是@Component("name")(或@Service("name")

  1. 据我所知,您只能使用String键将Maps自动连线,其中key是bean的名称。但是,您可以像这样轻松地将此地图转换为枚举键地图:
interface SomeInterface

@Component("one")
class OneClass: SomeInterface

@Component("two")
class TwoClass: SomeInterface

@Component("three")
class ThreeClass: SomeInterface

@Component
@ConfigurationProperties
class SomeProperties(implMap: Map<String, SomeInterface>) {

    val someMap: Map<SomeEnum, SomeInterface> = implMap.mapKeys {
        SomeEnum.values().firstOrNull { e -> e.value == it.key }!!
    }
}

已更新:

或使用场注入(不推荐)

@Component
@ConfigurationProperties
class SomeProperties {
    private lateinit var someMap: Map<SomeEnum, SomeInterface>

    @Autowired
    private lateinit var implMap: Map<String, SomeInterface>

    @PostConstruct
    fun initMap() {
        someMap = implMap.mapKeys {
            SomeEnum.values().firstOrNull { e -> e.value == it.key }!!
        } 
    }
}