Spring Boot: 可配置的primary datasource 博客分类: spring spring
程序员文章站
2024-03-17 22:26:34
...
Spring boot有多个数据源时, 必须有一个是primary的, 否则无法启动.
一般我们设置某个bean为primary时, 是添加primary注解, 如:
@Primary @Bean(name = "myDataSource1") public DataSource dataSource(Environment environment) { //.... }
通过@Primary将"myDataSource1"设置为primary的数据源. 缺点是不够灵活, 直接在代码里面写死了.
设想有如下两个数据源:
@Primary @Bean(name = "myDataSource1") @ConditionalOnProperty(prefix = "myCompany.datasource.myDataSource1", name = {"driverClassName", "url", "username", "password"}) public DataSource dataSource1(Environment environment) { //.... } @Bean(name = "myDataSource2") @ConditionalOnProperty(prefix = "myCompany.datasource.myDataSource2", name = {"driverClassName", "url", "username", "password"}) public DataSource dataSource2(Environment environment) { //.... }
假如myDataSource1的ConditionalOnProperty不满足, 则myDataSource1不会被创建.则整个应用就没有primary的数据源, 应用就无法启动了. 所以更好的写法是当myDataSource1存在时就设置其为primary; 否则设置myDataSource2为primary.
首先去掉myDataSource1上的@Primary注解, 然后添加PrimaryDataSourcePostProcessor.
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.Environment; /** * Set primary datasource. * * @author rickg@iteye.com on 2017/3/10. */ public class PrimaryDataSourcePostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware { private Environment environment; @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { setPrimaryDataSource(beanFactory); } private void setPrimaryDataSource(ConfigurableListableBeanFactory beanFactory) { try { BeanDefinition dsBeanDefinition1 = beanFactory.getBeanDefinition("myDataSource1"); dsBeanDefinition1.setPrimary(true); } catch (NoSuchBeanDefinitionException e) { BeanDefinition dsBeanDefinition2 = beanFactory.getBeanDefinition("myDataSource2"); dsBeanDefinition2.setPrimary(true); } } @Override public void setEnvironment(Environment environment) { this.environment = environment; } }
注意到上面的代码注入了Environment, 所以可以从Environment中读取配置,根据配置来决定设置哪个datasource为primary, 就比较灵活了.
最后注册BeanDefinitionRegistryPostProcessor, 完毕.
@Bean(name = "primaryDataSourcePostProcessor") public BeanDefinitionRegistryPostProcessor primaryDataSourcePostProcessor() { LOG.info(">>>>>>>initializing primaryDataSourcePostProcessor"); return new PrimaryDataSourcePostProcessor(); }
推荐阅读
-
Spring:一主多从DataSource的读写分离实现 博客分类: spring AbstractRoutingDataSourceSpring
-
Spring Boot: 可配置的primary datasource 博客分类: spring spring
-
SpringBoot2.0的CacheManager配置 博客分类: spring SpringBoot
-
升级spring boot 2.0遇到的问题汇总 博客分类: spring springboot2.0
-
升级spring boot 2.0遇到的问题汇总 博客分类: spring springboot2.0
-
SpringBoot2.0的CacheManager配置 博客分类: spring SpringBoot
-
Spring事务配置的五种方式 博客分类: AOPSpring Spring事务配置的五种方式
-
spring cloud eureka 参数配置 博客分类: spring boot 实践笔记 eureka 参数
-
自定义spring cloud eureka client的instance-id 博客分类: spring boot 实践笔记 eureka client instance-id
-
springboot2.4.1跨域设置的变化 博客分类: spring boot 实践笔记 springboot2.4.1跨域