在初学习springboot的过程中,有一些东西,让我百思不能其解,盲猜就是源码
我以为的注入是这样的
@Configuration public class JdbcConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource getData(){
DruidDataSource druidDataSource=new DruidDataSource();
return druidDataSource;
} }
然后通过@Resource或者@Autowired进行自动装配
@RestController
public class TestController {
private static final Logger log = LoggerFactory.getLogger(TestController.class);
@Resource
private DataSource source;
}
但是当我加入jar或者依赖时候发生类似于这样的代码
@SpringBootTest
class Springboot04DataApplicationTests {
@Autowired
DataSource dataSource;
@Test
void contextLoads() throws SQLException {
System.out.println(dataSource.getClass());
Connection connection=dataSource.getConnection();
System.out.println(connection);
connection.close();
}
}
本人属实刚学笨拙,殊不知springboot已经在我导入jar的时候就进行了自动装配到容器里,再次也要感谢狂神的讲解,但是上来讲源码属实枯燥,我重新回顾发现,其实狂神讲过了,可能是走神了
对此我查阅了一些文章和自己的总结
我们在使用spring boot的时候我们配置一个数据源主要是通过如下配置来进行定义
配置数据源的类型,比如druid,不配置会使用默认的数据源类型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
配置数据源的数据库服务地址
spring:
datasource:
username: root
password: 281913
url: jdbc:mysql://localhost:3306/mybatis?&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
配置数据源的驱动类
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
配置数据源数据库服务的用户名称
spring.datasource.username=root
配置数据源数据库服务的用户密码
spring.datasource.password=281913
就这样配置完成后,在spring ioc容器中就会有一个beanName=dataSource的bean实例。
2、自动配置数据源的原理分析
spring-boot-autoconfigure我们去查找数据源自动配置的配置类,结果如下:
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
2.2、我们重点关注的是DataSourceAutoConfiguration这个配置类,其他的都大同小异,DataSourceAutoConfiguration是一个配置类,我们第一关注的就是这个类上面的注解:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(
type = {"io.r2dbc.spi.ConnectionFactory"}
)
第一查看的是@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) 在类路径下要有这两个类才会激活当前配置类,DataSource是javax.sql.DataSource 肯定是已经存在当前类路径下的,EmbeddedDatabaseType这个类的全路径是啥呢??
经过查看源码我们发现是org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType类型,那么这个类在什么包里面呢? 我们需要怎样引入依赖呢?
经过查看源码我们发现EmbeddedDatabaseType这个类存在于spring-jdbc这个jar包里面,那么是不是我们引入spring-jdbc这个jar包后就能激活DataSourceAutoConfiguration这个配置类呢? 答案是肯定的,我们引入spring-jdbc的jar包后,我们配置文件中配置数据的配置如下:我们会发现在springIOC容器中果然配置好了一个datasource实例。
配置数据源的类型,比如druid,不配置会使用默认的数据源类型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
配置数据源的数据库服务地址
spring.datasource.url=jdbc:mysql://localhost:3306/test?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8
配置数据源的驱动类
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
配置数据源数据库服务的用户名称
spring.datasource.username=root
配置数据源数据库服务的用户密码
spring.datasource.password=281913
我们通过引入spring-jdbc的jar包后可以完成我们的数据源DataSource的配置,但是这样引入的话我们还需要关系spring-jdbc的版本问题,不是很方便,因此spring boot提供了一个启动包spring-boot-starter-jdbc,这个jar的pom.xml如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
我们可以看出来,spring-boot-starter-jdbc这个启动包引入了spring-jdbc、HikariCP这个两个很重要的包,既然引入了spring-jdbc这个包,那么我们的DataSourceAutoConfiguration这个配置类就被激活了,那么为什么好要引入HikariCP这个包呢?HikariCP这个包是一个数据源,有小日本开发的,据说性能第一,这也是在spring boot中默认使用的数据源。
引入HikariCP这个包后,是怎样实现默认配置的数据源类型是HikariCP是呢?????
在DataSourceAutoConfiguration这个类中定义了如下bean定义:
@Configuration(proxyBeanMethods = false)
@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 {
}
我们可以看到会导入4中数据源的配置类,分别如下:
1、Hikari : 提供配置HikariDataSource
2、Tomcat :提供配置org.apache.tomcat.jdbc.pool.DataSource
3、Dbcp2 :org.apache.commons.dbcp2.BasicDataSource
4、Generic :如果配置了spring.datasource.type属性就按照配置的数据源类型来配置数据源。比如Druid。
我们来查看DataSourceConfiguration.Hikari这个配置类,源码如下:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
类路径下必须存在HikariDataSource这个类
@ConditionalOnMissingBean(DataSource.class)
当前容器中存在DataSource类型的bean
如果spring.datasource.type配置了,如果配置的值为com.zaxxer.hikari.HikariDataSource
或者没有配置spring.datasource.type这个值 那就激活HikariDataSource的自动配置类。
@ConditionalOnProperty(name = “spring.datasource.type”, havingValue = “com.zaxxer.hikari.HikariDataSource”,
static class Hikari {
@Bean
这个注解表示我们可以指定配置以spring.datasource.hikari为前缀的配置项来配置hikari数据源
例如:spring.datasource.hikari.jdbc-url=xxx
spring.datasource.hikari.driver-class-name=xxx
spring.datasource.hikari.username=xxx
spring.datasource.hikari.password=xxx …
@ConfigurationProperties(prefix = “spring.datasource.hikari”)
那么为什么我们不配置以spring.datasource.hikari为前缀的配置项如spring.datasource.url
等配置也能生效呢?此处的properties就是我们配置的spring.datasource.url等配置项,毫无疑问spring
boot肯定帮我们做了映射,源码中也确实发现了,有兴趣的可以自行调试。
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = createDataSource(properties,
HikariDataSource.class); if
(StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName()); } return dataSource; } }
接着我们来看看DataSourceConfiguration.Dbcp2配置类的实现,源码如下:
/** * DBCP DataSource configuration. */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
这里也是如果没有配置spring.datasource.type或者
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource的时候激活了,那么问题来了,如果我同时激活Hikari、Dbcp2且不配置spring.datasource.type,那么最后究竟会选择哪一个呢?????
@ConditionalOnProperty(name = “spring.datasource.type”,
havingValue = “org.apache.commons.dbcp2.BasicDataSource”,
matchIfMissing = true)
static class Dbcp2 {
@Bean
@ConfigurationProperties(prefix =
“spring.datasource.dbcp2”) org.apache.commons.dbcp2.BasicDataSource
dataSource(DataSourceProperties properties) {
return createDataSource(properties,
org.apache.commons.dbcp2.BasicDataSource.class); }
}上面抛出了问题,如果激活了两种数据源你的配置类,会以那种数据源的配置类配置数据源,经过测试还是会选择Hikari。
最后我们来说一下 ,DataSourceConfiguration.Generic 源码如下:
/**
* Generic DataSource configuration.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(DataSource.class)
如果配置了 spring.datasource.type属性就激活,如果配置的spring.datasource.type不是其他数据源
类型的,就会使用次数据源配置类,会根据配置的数据源类型来进行数据源配置,比如配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 是阿里的druid,那么最后配置的数
据源就是DruidDataSource。
@ConditionalOnProperty(name = “spring.datasource.type”) static class
Generic {
@Bean DataSource dataSource(DataSourceProperties properties) { return properties.initializeDataSourceBuilder().build(); } }
整个数据源的配置原理就是这样。
——————————————
文章内容基本上来源🐟这里
我不得不说,我本人真的看不懂源码,想弄清楚一些东西,真挺难
、