欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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