zoukankan      html  css  js  c++  java
  • spring boot自动配置之jdbc

    1.DataSource配置

    1.1 默认配置application.xml

    spring.datasource.url=jdbc:mysql://localhost/test
    spring.datasource.username=root
    spring.datasource.password=****
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.type=com.zaxxer.hikari.HikariDataSource

    需要在pom.xml加入依赖(我使用了mybatis+mysql)

          <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
          </dependency>
          <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis-spring.version}</version>
          </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
        </dependency>   

       <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <exclusions>
          <exclusion>
            <artifactId>tools</artifactId>
            <groupId>com.sun</groupId>
          </exclusion>
        </exclusions>
      </dependency>

    2.自定义DataSource

    1.1 application.xml配置文件

    spring:
      application:
        name: data-multidatasource
        datasource:
            type: com.zaxxer.hikari.HikariDataSource
            url: jdbc:mysql://localhost:3306/test
            username: sa
            password: ****
      second-datasource:
        driver-class-name: org.hsqldb.jdbc.JDBCDriver
        url: jdbc:hsqldb:mem:db2
        username: sa
        password:****

    1.2 自定义DataSource配置

    @Configuration
    public class SencondDataSourceConfiguration {
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource newDataSource() {
            return DataSourceBuilder.create().build();
        }
    
        @Bean(name = "secondDatasource")
        @ConfigurationProperties(prefix = "spring.second-datasource")
        public DataSource secondDataSource() {
            return DataSourceBuilder.create().build();
        }
    }

    3.工作原理

     spring boot的auto-configuration最具魔力的地方是@EnableAutoConfiguration注解

     通常注解application应用使用@SpringBootApplication或者如下自定义的方式:

    @Configuration
    
    @EnableAutoConfiguration
    
    @ComponentScan
    
    public class Application
    
    {
    
    }

    @EnableAutoConfiguration注解开启了spring ApplicationContext的自动配置功能,

    它通过扫描classpath下的组件,满足不同Conditions的bean注册到容器中。

    spring boot提供了不同的AutoConfiguration实现类,这些类都在spring-boot-autoconfigure-{version}.jar中,用来注册各种各样的组件。

    通常,当AutoConfiguration实现类打上@Configuration标签,可以作为spring配置类,当AutoConfiguration实现类打上@EnableConfigurationProperties标签,可以绑定自定义属性或者更多Conditional bean注册方法。

    下面就org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration来分析一下:

    /**
     * {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource}.
     *
     * @author Dave Syer
     * @author Phillip Webb
     * @author Stephane Nicoll
     * @author Kazuki Shimizu
     */
    @Configuration
    @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
    @EnableConfigurationProperties(DataSourceProperties.class)
    @Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
    public class DataSourceAutoConfiguration {
    
        private static final Log logger = LogFactory
                .getLog(DataSourceAutoConfiguration.class);
    
        @Bean
        @ConditionalOnMissingBean
        public DataSourceInitializer dataSourceInitializer(DataSourceProperties properties,
                ApplicationContext applicationContext) {
            return new DataSourceInitializer(properties, applicationContext);
        }
    
        /**
         * Determines if the {@code dataSource} being used by Spring was created from
         * {@link EmbeddedDataSourceConfiguration}.
         * @param beanFactory the bean factory
         * @return true if the data source was auto-configured.
         */
        public static boolean containsAutoConfiguredDataSource(
                ConfigurableListableBeanFactory beanFactory) {
            try {
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition("dataSource");
                return EmbeddedDataSourceConfiguration.class.getName()
                        .equals(beanDefinition.getFactoryBeanName());
            }
            catch (NoSuchBeanDefinitionException ex) {
                return false;
            }
        }
    
        @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.Tomcat.class, DataSourceConfiguration.Hikari.class,
                DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class })
        protected static class PooledDataSourceConfiguration {
    
        }
    
        @Configuration
        @ConditionalOnProperty(prefix = "spring.datasource", name = "jmx-enabled")
        @ConditionalOnClass(name = "org.apache.tomcat.jdbc.pool.DataSourceProxy")
        @Conditional(DataSourceAutoConfiguration.DataSourceAvailableCondition.class)
        @ConditionalOnMissingBean(name = "dataSourceMBean")
        protected static class TomcatDataSourceJmxConfiguration {
    
            @Bean
            public Object dataSourceMBean(DataSource dataSource) {
                if (dataSource instanceof DataSourceProxy) {
                    try {
                        return ((DataSourceProxy) dataSource).createPool().getJmxPool();
                    }
                    catch (SQLException ex) {
                        logger.warn("Cannot expose DataSource to JMX (could not connect)");
                    }
                }
                return null;
            }
    
        }
    
        /**
         * {@link AnyNestedCondition} that checks that either {@code spring.datasource.type}
         * is set or {@link PooledDataSourceAvailableCondition} applies.
         */
        static class PooledDataSourceCondition extends AnyNestedCondition {
    
            PooledDataSourceCondition() {
                super(ConfigurationPhase.PARSE_CONFIGURATION);
            }
    
            @ConditionalOnProperty(prefix = "spring.datasource", name = "type")
            static class ExplicitType {
    
            }
    
            @Conditional(PooledDataSourceAvailableCondition.class)
            static class PooledDataSourceAvailable {
    
            }
    
        }
    
        /**
         * {@link Condition} to test if a supported connection pool is available.
         */
        static class PooledDataSourceAvailableCondition extends SpringBootCondition {
    
            @Override
            public ConditionOutcome getMatchOutcome(ConditionContext context,
                    AnnotatedTypeMetadata metadata) {
                ConditionMessage.Builder message = ConditionMessage
                        .forCondition("PooledDataSource");
                if (getDataSourceClassLoader(context) != null) {
                    return ConditionOutcome
                            .match(message.foundExactly("supported DataSource"));
                }
                return ConditionOutcome
                        .noMatch(message.didNotFind("supported DataSource").atAll());
            }
    
            /**
             * Returns the class loader for the {@link DataSource} class. Used to ensure that
             * the driver class can actually be loaded by the data source.
             * @param context the condition context
             * @return the class loader
             */
            private ClassLoader getDataSourceClassLoader(ConditionContext context) {
                Class<?> dataSourceClass = new DataSourceBuilder(context.getClassLoader())
                        .findType();
                return (dataSourceClass == null ? null : dataSourceClass.getClassLoader());
            }
    
        }
    
        /**
         * {@link Condition} to detect when an embedded {@link DataSource} type can be used.
         * If a pooled {@link DataSource} is available, it will always be preferred to an
         * {@code EmbeddedDatabase}.
         */
        static class EmbeddedDatabaseCondition extends SpringBootCondition {
    
            private final SpringBootCondition pooledCondition = new PooledDataSourceCondition();
    
            @Override
            public ConditionOutcome getMatchOutcome(ConditionContext context,
                    AnnotatedTypeMetadata metadata) {
                ConditionMessage.Builder message = ConditionMessage
                        .forCondition("EmbeddedDataSource");
                if (anyMatches(context, metadata, this.pooledCondition)) {
                    return ConditionOutcome
                            .noMatch(message.foundExactly("supported pooled data source"));
                }
                EmbeddedDatabaseType type = EmbeddedDatabaseConnection
                        .get(context.getClassLoader()).getType();
                if (type == null) {
                    return ConditionOutcome
                            .noMatch(message.didNotFind("embedded database").atAll());
                }
                return ConditionOutcome.match(message.found("embedded database").items(type));
            }
    
        }
    
        /**
         * {@link Condition} to detect when a {@link DataSource} is available (either because
         * the user provided one or because one will be auto-configured).
         */
        @Order(Ordered.LOWEST_PRECEDENCE - 10)
        static class DataSourceAvailableCondition extends SpringBootCondition {
    
            private final SpringBootCondition pooledCondition = new PooledDataSourceCondition();
    
            private final SpringBootCondition embeddedCondition = new EmbeddedDatabaseCondition();
    
            @Override
            public ConditionOutcome getMatchOutcome(ConditionContext context,
                    AnnotatedTypeMetadata metadata) {
                ConditionMessage.Builder message = ConditionMessage
                        .forCondition("DataSourceAvailable");
                if (hasBean(context, DataSource.class)
                        || hasBean(context, XADataSource.class)) {
                    return ConditionOutcome
                            .match(message.foundExactly("existing data source bean"));
                }
                if (anyMatches(context, metadata, this.pooledCondition,
                        this.embeddedCondition)) {
                    return ConditionOutcome.match(message
                            .foundExactly("existing auto-configured data source bean"));
                }
                return ConditionOutcome
                        .noMatch(message.didNotFind("any existing data source bean").atAll());
            }
    
            private boolean hasBean(ConditionContext context, Class<?> type) {
                return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        context.getBeanFactory(), type, true, false).length > 0;
            }
    
        }
    
    }

    从上面看到,

    1. DataSourceAutoConfiguration打上了@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })标签,这意味着只有当DataSource.class和EmbeddedDatabaseType.class出现在classpath时,DataSourceAutoConfiguration内的自动配置bean才可能被注册。

    2. DataSourceAutoConfiguration打上了@EnableConfigurationProperties(DataSourceProperties.class)标签,意味着application.properties中的属性和DataSourceProperties类自动绑定了。

    @ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
    
    public class DataSourceProperties implements BeanClassLoaderAware, EnvironmentAware, InitializingBean {
    
     public static final String PREFIX = "spring.datasource";
    
     ...
    
     ...
    
     private String driverClassName;
    
     private String url;
    
     private String username;
    
     private String password;
    
     ...
    
     //setters and getters
    
    }

    上面的配置类中说明,在application.properties中以spring.datasource开头的属性将自动绑定到DataSourceProperties对象上。其他注解,如@ConditionalOnMissingBean, @ConditionalOnClass and @ConditionalOnProperty等,标识只要条件满足,bean definition将注册到ApplicationContext中。

    参考文件:

    【1】http://www.liaoxuefeng.com/article/001484212576147b1f07dc0ab9147a1a97662a0bd270c20000

    【2】https://dzone.com/articles/how-springboot-autoconfiguration-magic-works

  • 相关阅读:
    let与const的区别
    IOS客户端UIwebview下web页面闪屏问题
    移动端click事件延迟300ms问题
    css3+visbibilty解决淡入淡出问题
    git学习之branch分支
    git学习之冲突解决办法
    webpack+vue-cli项目打包技巧
    一个高级PHP工程师所应该具备的
    多站点
    PHP error_reporting() 错误控制函数功能详解
  • 原文地址:https://www.cnblogs.com/davidwang456/p/6600550.html
Copyright © 2011-2022 走看看