初学初探源码 关于自动装配【springboot】

在初学习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(); } }

整个数据源的配置原理就是这样。
——————————————
文章内容基本上来源🐟这里
我不得不说,我本人真的看不懂源码,想弄清楚一些东西,真挺难

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爪哇贡尘拾Miraitow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值