Spring Boot: 可配置的primary datasource

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 [email protected] 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();
    }

猜你喜欢

转载自rickgong.iteye.com/blog/2367417
今日推荐