Druid-spring-boot-starter源码阅读-DataSource自动配置实现

17 篇文章 1 订阅
5 篇文章 0 订阅

最近在看Druid-spring-boot-starter模块,简单记录下。

我看的源码版本是1.2.20。

为啥有两个模块

可以看到项目里面有两个spring-boot-starter。而且看着大部分是一样的,为啥会有两个呢?

看着是为了兼容spring-boot 3.0及以上版本,因为在springboot3.0之后,自动配置的加载方式有了变化,3.0之前是spring.factories,3.0之后变成了META-INF/spring/org.springframework.boot.autoconfigure.AutoConfigurtoation.imports里,所以需要一个单独的模块去支持springboot3.0之后的加载方式,看github上的issue好像还有一些其他特性需要兼容,所以分了两个模块。

自动配置流程

我们这里以druid-spring-boot-3-starter为例,从配置文件可以看到入口在DruidDataSourceAutoConfigure这个类:

@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();
    }
}

它的实现其实比较简单,从上往下看,首先你要导入了Druid相关的包才会进行自动配置,然后它是DataSource自动装配之前,Druid是构件在数据源之上的一层封装,需要在装配数据源之前初始化完成。读取两个属性配置类DruidStatProperties和DataSourceProperties,后者是前者的补充,如果没有设置任何druid相关的参数,但是引入了druid的库,会直接用spring.datasource设置的jdbc属性。然后初始化Druid。最后引入了一些配置,包括AOP,监控页面,web-stat-filter配置,其他filter配置。

具体哪些值是可配的可以参考官方文档或者直接查看DruidStatProperties类的属性。

然后里面的会创建一个DruidDataSourceWrapper,注意这个类是同时实现了InitializingBean接口和initMethod方法的,但是会先执行afterPropertiesSet在执行init方法。

整个类实现很简单:

@ConfigurationProperties("spring.datasource.druid")
public class DruidDataSourceWrapper extends DruidDataSource implements InitializingBean {
    @Autowired
    private DataSourceProperties basicProperties;

    @Override
    public void afterPropertiesSet() throws Exception {
        //if not found prefix 'spring.datasource.druid' jdbc properties ,'spring.datasource' prefix jdbc properties will be used.
        if (super.getUsername() == null) {
            super.setUsername(basicProperties.determineUsername());
        }
        if (super.getPassword() == null) {
            super.setPassword(basicProperties.determinePassword());
        }
        if (super.getUrl() == null) {
            super.setUrl(basicProperties.determineUrl());
        }
        if (super.getDriverClassName() == null) {
            super.setDriverClassName(basicProperties.getDriverClassName());
        }
    }

    @Autowired(required = false)
    public void autoAddFilters(List<Filter> filters) {
        super.filters.addAll(filters);
    }

    /**
     * Ignore the 'maxEvictableIdleTimeMillis &lt; minEvictableIdleTimeMillis' validate,
     * it will be validated again in {@link DruidDataSource#init()}.
     * <p>
     * for fix issue #3084, #2763
     *
     * @since 1.1.14
     */
    @Override
    public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
        try {
            super.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
        } catch (IllegalArgumentException ignore) {
            super.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
        }
    }
}

初看可能觉得比较奇怪,有几个问题

  1. 这里面没有init方法,它执行的什么呢?
  2. 这里面完全没有参数赋值,它那么多参数怎么赋值的呢?

答案都是在父类DruidDataSource里,它里面的init方法会被调用,且因为@ConfigurationProperties("spring.datasource.druid")注解,所有符合条件的参数都会被赋值,比如spring.datasource.druid.userName,就会赋值给DruidDataSource的userName属性,所以注释里才会有所谓的如果没有spring.datasource.druid会使用spring.datasource的说法。

总结

可以看到整个自动配置还是比较简单的,核心是在spring加载其他DataSource之前创建DruidDataSource并完成初始化。

  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值