springboot2.0整合druid,以及springboot自动装配DataSource原理_Java_鸭鸭的博客-CSDN博客

1.springboot 目前的推荐版是2.1.2.RELEASE,我们就以当前最新的推荐版为例

2.创建项目,引入对应的jar包,我是以maven的形式

父级的pom

<parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>2.1.2.RELEASE</version>        <relativePath /> <!-- lookup parent from repository -->    </parent>

 引入的包

<dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-jdbc</artifactId>        </dependency>         <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>druid-spring-boot-starter</artifactId>            <version>1.1.10</version>        </dependency>

3.配置文件,更新详细的配置 请参考 阿里的github查看,网址;里面介绍了更详细的属性含义,以及多数据源的配置方式

spring:  datasource:    url: jdbc:mysql://localhost:3306/test    username: root    password: 613814    driver-class-name: com.mysql.jdbc.Driver    type: com.alibaba.druid.pool.DruidDataSource    druid:      initial-size: 8      min-idle: 1      max-active: 20      max-wait: 60000      time-between-eviction-runsMillis: 60000      min-evictable-idle-timeMillis: 300000      validation-query: select 'x' FROM DUAL      test-while-idle: true      test-on-borrow: false      test-on-return: false      pool-prepared-statements: true      max-open-prepared-statements: 20      max-pool-prepared-statement-per-connection-size: 20      filters: stat      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000      use-global-data-source-stat: true

4.测试类,debug运行,可以看到,DataSource接口的实现类就是durid的实现类,可以继续找到配置文件中的一些初始化参数

      initial-size: 8
      min-idle: 1
      max-active: 20
      max-wait: 60000

@RunWith(SpringRunner.class)@SpringBootTest(classes = { BadgerDruidApplication.class })public class BadgerDruidApplicationTests {     @Autowired    DataSource dataSource;     @Test    public void contextLoads() throws SQLException {        Connection connection = dataSource.getConnection();        PreparedStatement prepareStatement = connection                .prepareStatement("select * from t_city where parent_id='-1'");        ResultSet resultSet = prepareStatement.executeQuery();        while (resultSet.next()) {            String cityName = resultSet.getString("name");            System.out.println(cityName);        }    }}

至此,druid就与springboot2.0集成完成了;当然中间也会有springboot2.0 mysql的驱动包,跟服务端版本不匹配的异常

java.sql.SQLNonTransientConnectionException: CLIENT_PLUGIN_AUTH is required

替换下mysql驱动的版本

<properties>        <java.version>1.8</java.version>        <mysql.version>5.1.6</mysql.version>    </properties>

5.下面讲一点springboot对DataSource的一些自动装配原理,以及另一种druid的方式

spring-boot-autoconfigure-2.1.2.RELEASE.jar包下的org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration类

@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 {     }     /**     * {@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 {         }     }

我们先看类上@Import({ DataSourcePoolMetadataProvidersConfiguration.class,DataSourceInitializationConfiguration.class })

DataSourcePoolMetadataProvidersConfiguration导入这个类的实例,点进去可以看到

@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)

@ConditionalOnClass(HikariDataSource.class)

@ConditionalOnClass(BasicDataSource.class)

这3个数据源的装配,都是导入了这些数据源,才会实例创建成功;而springboot2.0的默认生效的HikariDataSource数据源;如图所示,spring-boot-starter-jdbc默认依赖了;而在springboot1.x中,默认生效的org.apache.tomcat.jdbc.pool.DataSource.class

现在我们看下根据spring.datasource.type指定类型的实例化,只拿了一部分主要的,我们主要来看PooledDataSourceConfiguration 这个内部类

    @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 {     }

@Conditional(PooledDataSourceCondition.class) 根据判断条件,实例化这个类,指定了配置文件中,必须有type这个属性

实例化后,@Import 会导入DataSourceConfiguration 这个类;在DataSourceConfiguration这个类中,就是具体的DataSource接口实现;我们默认导入web模块后,会导入tomcat,并且实例化org.apache.tomcat.jdbc.pool.DataSource

    /**     * Tomcat Pool DataSource configuration.     */     //只要导入了这个org.apache.tomcat.jdbc.pool.DataSource.class,就会生效    @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)    //没有DataSource的实例    @ConditionalOnMissingBean(DataSource.class)    //配置了spring.datasource.type 并且值为org.apache.tomcat.jdbc.pool.DataSource,才会生效;    //matchIfMissing=true表示,就算没有配置spring.datasource.type,也会生效    @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)    static class Tomcat {         @Bean        @ConfigurationProperties(prefix = "spring.datasource.tomcat")        public org.apache.tomcat.jdbc.pool.DataSource dataSource(                DataSourceProperties properties) {            org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(                    properties, org.apache.tomcat.jdbc.pool.DataSource.class);            DatabaseDriver databaseDriver = DatabaseDriver                    .fromJdbcUrl(properties.determineUrl());            String validationQuery = databaseDriver.getValidationQuery();            if (validationQuery != null) {                dataSource.setTestOnBorrow(true);                dataSource.setValidationQuery(validationQuery);            }            return dataSource;        }     }

另外springboot 默认支持 type 类型设置的数据源;

@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
            DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
            DataSourceJmxConfiguration.class })

具体的,接着DataSourceConfiguration类看就可以了,

下面说下,集成druid 在DataSourceConfiguration类,最后的部分

    /**     * Generic DataSource configuration.     */    @ConditionalOnMissingBean(DataSource.class)    @ConditionalOnProperty(name = "spring.datasource.type")    static class Generic {         @Bean        public DataSource dataSource(DataSourceProperties properties) {            return properties.initializeDataSourceBuilder().build();        }     }

如果上面,都不生效,就会执行这个;我们直接看 return properties.initializeDataSourceBuilder().build(); 这个build方法;

@SuppressWarnings("unchecked")    public T build() {        Class<? extends DataSource> type = getType();        DataSource result = BeanUtils.instantiateClass(type);        maybeGetDriverClassName();        bind(result);        return (T) result;    }

拿到上述配置文件中的com.alibaba.druid.pool.DruidDataSource 这个类的全类名,反射实例化;至此,datasource的实例过程,就说完了;最后我们看下,阿里官方封装的druid-spring-boot-starter,直接简单粗暴的创建了一个datasource的实现,有感性的朋友,也可以看下DruidDataSourceWrapper 的具体实现,就不在继续描述

@Configuration@ConditionalOnClass(DruidDataSource.class)@AutoConfigureBefore(DataSourceAutoConfiguration.class)@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})@Import({DruidSpringAopConfiguration.class,    DruidStatViewServletConfiguration.class,    DruidWebStatFilterConfiguration.class,    DruidFilterConfiguration.class})public class DruidDataSourceAutoConfigure {     private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);     @Bean(initMethod = "init")    @ConditionalOnMissingBean    public DataSource dataSource() {        LOGGER.info("Init DruidDataSource");        return new DruidDataSourceWrapper();    }}

原网址: 访问
创建于: 2020-05-06 01:31:28
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论