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

Guide reading

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 a good idea?
  • 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 line, @ 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. See DataSourceTransactionManagerAutoConfiguration as follows:
public class DataSourceTransactionManagerAutoConfiguration {

    @Configuration
    @ConditionalOnSingleCandidate(DataSource.class)
    static class DataSourceTransactionManagerConfiguration {
  • What else do you see, @ ConditionalOnSingleCandidate(DataSource.class) is equally eye-catching, mmp. Don't you play me. What's the matter?
  • Eh, don't worry. Now let's see what happened to the @ ConditionalOnSingleCandidate annotation. Go in and have a look. Here's 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:

  • 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:
/**
 * @Description Configuration of 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<Object, Object> 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;
    }
}
  • Adding a @ Primary to DynamicDataSource directly saves the manual configuration of SqlSessionFactory and TransactionManager. Isn't it easy and seems like you're 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:

  • 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, you need to contact me with the source code. Wechat contact information is in Personal independent blog In [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

  • Preceding articles Spring solves circular dependency It has been said that Spring can completely solve circular dependency. For those who haven't read it, I suggest you take a look. 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:

  • The above two data sources are self-defined. If you don't need to look at them first, it must be the circular dependency caused by DataSourceInitializerInvoker. Sure enough, it does depend on DataSource. The source code is as follows:
DataSourceInitializerInvoker(ObjectProvider<DataSource> 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. Please read for the reason Spring de cyclic 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? Very simply, find out when the DataSourceInitializerInvoker was injected into the IOC container, so we found DataSourceAutoConfiguration, and then found the configuration class DataSourceInitializationConfiguration. The source code 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? We can see that @ conditionalonmissingbean ({datasource. Class, xadatasource. Class}) has appeared twice in the source code. I don't need to say more about it. I'm sure anyone who has read the spring boot source code knows that this configuration class doesn't work at all. What else should it do? It can't be done directly. OK, we finally know the solution after analysis. What can we do if we get rid of DataSourceAutoConfiguration? 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....

I have something to say

  • If you need Java learning materials or want to have in-depth communication, please private mail or Please contact me.

Tags: Java Spring SpringBoot Mybatis Tomcat

Posted on Wed, 18 Mar 2020 05:43:02 -0400 by xSN1PERxEL1TEx