1.springboot 目前的推荐版是2.1.2.RELEASE,咱们就以当前最新的推荐版为例java
2.建立项目,引入对应的jar包,我是以maven的形式mysql
父级的pomgit
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent>
引入的包github
<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查看,网址;里面介绍了更详细的属性含义,以及多数据源的配置方式web
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的实现类,能够继续找到配置文件中的一些初始化参数spring
initial-size: 8
min-idle: 1
max-active: 20
max-wait: 60000sql
@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的驱动包,跟服务端版本不匹配的异常apache
java.sql.SQLNonTransientConnectionException: CLIENT_PLUGIN_AUTH is requiredtomcat
替换下mysql驱动的版本springboot
<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(); } }