基于application.properties配置注入指定Spring接口实现类
根据配置动态注入Spring接口实现的解决方案
这个需求在Spring开发中挺常见的,不用纠结要不要移除@Component,有两种非常实用的方式可以搞定,我给你详细说说:
方案1:保留@Component,用@ConditionalOnProperty做条件注册
这种方式不用修改现有实现类的结构,只需要给每个实现类加上条件注解,让Spring根据配置决定注册哪个Bean:
- 给
HahaImpl1添加条件注解,匹配配置值impl1:
@Component @ConditionalOnProperty(name = "myApp.haha", havingValue = "impl1") class HahaImpl1: Haha { @Autowired lateinit var repo: JpaRepository<Data, Long> }
- 给
HahaImpl2添加对应的条件注解,匹配配置值impl2:
@Component @ConditionalOnProperty(name = "myApp.haha", havingValue = "impl2") class HahaImpl2: Haha
然后在application.properties里配置:
myApp.haha=impl1
此时Spring只会将HahaImpl1注册为容器中的Bean,Yoyo服务里的@Autowired lateinit var haha: Haha就能自动注入正确的实现;把配置改成impl2,就会注入HahaImpl2。
方案2:移除@Component,用配置类动态创建Bean
如果你不想在实现类上添加额外注解,可以移除它们的@Component,然后写一个配置类来根据配置逻辑生成对应的Bean:
方式A:基于分支判断创建Bean
@Configuration class HahaConfig { @Value("\${myApp.haha}") private lateinit var hahaType: String @Bean fun haha(repo: JpaRepository<Data, Long>): Haha { return when(hahaType) { "impl1" -> HahaImpl1().apply { this.repo = repo } "impl2" -> HahaImpl2() else -> throw IllegalArgumentException("不支持的Haha实现类型:$hahaType") } } }
这里注意HahaImpl1需要的repo可以直接作为方法参数,Spring会自动帮你注入依赖。
方式B:用@ConditionalOnProperty标注单个Bean方法
这种方式更清晰,每个Bean的创建条件一目了然:
@Configuration class HahaConfig { @Bean @ConditionalOnProperty(name = "myApp.haha", havingValue = "impl1") fun hahaImpl1(repo: JpaRepository<Data, Long>): Haha { return HahaImpl1().apply { this.repo = repo } } @Bean @ConditionalOnProperty(name = "myApp.haha", havingValue = "impl2") fun hahaImpl2(): Haha { return HahaImpl2() } }
额外优化建议
为了避免配置错误导致没有可用的Haha Bean,可以添加一个默认实现,比如:
@Component @ConditionalOnProperty(name = "myApp.haha", havingValue = "default", matchIfMissing = true) class HahaDefaultImpl: Haha
这样当配置未设置或者值为default时,会自动注入这个默认实现,避免启动报错。
内容的提问来源于stack exchange,提问作者maslick
相关产品推荐
相关产品推荐

