Springboot integrates the huge pit of multiple data sources!!!

Time:2020-3-21

Guide reading

  • This article will be followed by the last one: springboot integrates multiple data sources. Do you know? At the end of the article, I left a few questions for you to think about, and they will be announced one by one today.

How to optimize configuration

  • In the above integration process, mybatis and transaction manager are also integrated. Why redefining them? Isn’t springboot configured for us? Note that the optimization here is to remove these two configurations, and directly use the automatic configuration of springboot, which is immediately advanced. When others see that your code is so simple, they can realize the switch of multiple data sources. Is that right?
  • How to get rid of it? Spring boot is inseparable from the automatic configuration class. See mybatisautoconfiguration, as follows:
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration implements InitializingBean {
  • There are not many posts. They are all rubbish. Just look at the first few lines, the eye-catching one,@ConditionalOnSingleCandidate(DataSource.class)What the hell? This annotation means that only one candidate object specified in the IOC container works, but we have injected several datasources, enough three. Does this work? That’s not bullshit.
  • The same is true for transaction manager. Let’s seeDataSourceTransactionManagerAutoConfigurationAs follows:
public class DataSourceTransactionManagerAutoConfiguration {

    @Configuration
    @ConditionalOnSingleCandidate(DataSource.class)
    static class DataSourceTransactionManagerConfiguration {
  • What do you see,@ConditionalOnSingleCandidate(DataSource.class)The same eye-catching, MMP, don’t you play with me. What’s the matter?
  • Eh, don’t worry. I’ll have a look at it now@ConditionalOnSingleCandidateWhat did the annotation do? Go in and have a look. Here is the introduction:
The condition will also match if multiple matching bean instances are already contained in the BeanFactory but a primary candidate has been defined; essentially, the condition match if auto-wiring a bean with the defined type will succeed.
  • What the hell? I can’t understand it. English is too poor. Don’t worry. Chen recommended an idea plug-in for you. Document translation is more focused on the professional terms of programmers, unlike XX degree translation, as follows:

Springboot integrates the huge pit of multiple data sources!!!

  • Well, if the translation is accurate, it will be known. The general meaning is that you are allowed to have multiple candidates in the IOC container, but you must have a primary candidate. It’s a flash of inspiration. Isn’t that the @ primary annotation? Shit, I’m too good.
  • If you don’t want to talk about it, just open it and make a note. At this time, the data source configuration is much simpler, as follows:
/**
 *Configuration of @ description data source
 * @Author CJB
 * @Date 2020/3/9 13:45
 */
@Configuration
@MapperScan(basePackages = {"com.vivachek.service.dao","com.vivachek.service.dao2"})
public class DatasourceConfig {

    /**
     *Injection data source 1
     */
    @ConfigurationProperties(prefix = "spring.datasource1")
    @Bean(value = "dataSource1")
    public DataSource dataSource1() {
        return new DruidDataSource();
    }

    /**
     *Second data source
     */
    @Bean(name = "dataSource2")
    @ConfigurationProperties(prefix = "spring.datasource2")
    public DataSource dataSource2() {
        return new DruidDataSource();
    }

    /**
     *Dynamic data source
     *
     * @return
     */
    @Bean
    @Primary
    public DynamicDataSource dynamicDataSource() {
        DynamicDataSource dataSource = new DynamicDataSource();
        //Default data source, which is used when no data source is switched
        dataSource.setDefaultTargetDataSource(dataSource2());
        HashMap map = Maps.newHashMap();
        map.put("dataSource1", dataSource1());
        map.put("dataSource2", dataSource2());
        //Set the data source map, and the dynamic switch is to get from the map according to the key
        dataSource.setTargetDataSources(map);
        return dataSource;
    }
}
  • Directly inDynamicDataSourceAdding a @ primary will eliminate the manual configuration of sqlsessionfactory and transactionmanager. Is it easy and seems like a great success
  • OK, the cow blows too. Let’s run. Wait 30 seconds with full expectation? What the hell? Failed. An exception was thrown, as follows:

Springboot integrates the huge pit of multiple data sources!!!

  • What the hell, cycle dependence is abnormal, what the plane is, ten thousand grass and mud horses are galloping on the boundless grassland……..
  • Don’t worry, there are follow-up, follow me, will update follow-up articles regularly. In addition, I need to contact the source code, wechat contact information in the personal independent blog [about me], add me to indicate the intention, thank you.
  • Don’t forget to like it. Come and walk more

Dynamic routing data source adds @ primary to report circular dependency exception

  • In the previous article, spring solves circular dependency. It has been said that spring can solve circular dependency completely. For those who haven’t read it, I suggest you take a look at it. It details how spring solves circular dependency. I won’t go into details here.
  • Since spring is able to solve circular dependency, why are circular dependency exceptions reported here? Let’s follow the code to see what kind of circular dependency it is, as follows:

Springboot integrates the huge pit of multiple data sources!!!

  • The above two data sources are defined by themselves. If you don’t need to look at them first, they must beDataSourceInitializerInvokerThe resulting loop depends on, sure enough, datasource. The source code is as follows:
DataSourceInitializerInvoker(ObjectProvider dataSource, DataSourceProperties properties,
            ApplicationContext applicationContext) {
        this.dataSource = dataSource;
        this.properties = properties;
        this.applicationContext = applicationContext;
    }
  • What? What if I depend on it? Can spring solve circular dependency? Don’t worry. Let’s analyze
  • Objectprovider should be no stranger. In fact, the internal part is to get beans from IOC containers. However, the turning point is… What is this? This is a constructor. Can spring solve the circular dependency of the constructor? The answer is no, so the reason is found. No more details here. For the reason, please read spring to solve the circular dependency
  • The problem is found. How to solve it? At this time, ten thousand grass and mud horses are galloping in my heart. How can I solve this problem?

  • Ha ha, at this time, I’ve inserted an advertisement. My independent blog has published many articles. If you are interested, you can collect them. There’s my wechat contact information in [about me], welcome to exchange.
  • Back to the point, how to solve it? It’s easy. Find thisDataSourceInitializerInvokerWhen was it injected into the IOC container, so we foundDataSourceAutoConfiguration, and we foundDataSourceInitializationConfigurationThe source code of this configuration class is as follows:

@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
    @Configuration
    @Conditional(EmbeddedDatabaseCondition.class)
    @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    @Import(EmbeddedDataSourceConfiguration.class)
    protected static class EmbeddedDatabaseConfiguration {

    }

    @Configuration
    @Conditional(PooledDataSourceCondition.class)
    @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
            DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
            DataSourceJmxConfiguration.class })
    protected static class PooledDataSourceConfiguration {

    }   
}
    
    
@Configuration
@Import({ DataSourceInitializerInvoker.class, DataSourceInitializationConfiguration.Registrar.class })
class DataSourceInitializationConfiguration {
  • Who can understand after posting so many codes? The grass mud horse is galloping again. You can see that it appears twice in the source code@ConditionalOnMissingBean({ DataSource.class, XADataSource.class }), I don’t need to talk about that. I believe anyone who has read the spring boot source code knows that this configuration class doesn’t work at all. Then what else should I do? It’s not the end of the matter if I get rid of it directly. Well, we’ve got the solution here. Let’s get itDataSourceAutoConfigurationWhat’s the matter? A note is done.
//Exclude configuration classes
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
  • The problem is solved easily. It’s simple. It’s not surprising. It’s not good. It’s galloping again….

  • Don’t say anything, point a recommendation!!!

微信搜索码猿技术专栏