SpringBoot数据库配置源码解析:自动配置注解解析

SpringBoot数据库配置源码解析Spring Boot 对主流的数据库都提供了很好的支持 , 打开 Spring Boot 项目中的 starters 会发现针对 data 提供了 15 个 starter 的支持 , 包含了大量的关系型数据库和非关系数据库的数据访问解决方案 。 而本章重点关注 Spring Boot 中数据源自动配置源码的实现 , 及核心配置类 DataSourceAutoConfiguration 和 Jdbc TemplateAutoConfiguration 等的用法 。
SpringBoot数据库配置源码解析:自动配置注解解析文章插图
自动配置注解解析
首先 , 我们以数据源的自动配置进行讲解 , 数据源的自动配置像其他自动配置一样 , 在META-INF/spring.factories 文件中注册了对应自动配置类 。
#自动配置org. springframework. boot . autoconfigure . EnableAutoConfiguration=\org . springframework. boot . autoconfigure. jdbc . DataSourceAutoConfiguration, \下面我们通过分析 DataSourceAutoConfiguration 类的源代码来学习数据库自动配置的机制 。 先看注解部分 。
@Configuration(proxyBeanMethods = false)@ConditionalOnClass({ DataSource. class, EmbeddedDatabaseType . class })@EnableConfigurationProperties (DataSourceProperties.class)@Import({ DataSourcePoolMetadataProvidersConfiguration.class,DataSourceInitializat ionConf iguration.class })public class DataSourceAutoConfiguration {}注解@ConditionalOnClass 要求类 路径下必须 有 DataSource 和 EmbeddedDatabaseType 类的存在 。 @EnableConfigurationProperties 属性会装配 DataSourceProperties 类 , 该配置类与 application.properties 中的配置相对应 。
比如 , 对于数据库我们经常在 application.properties 中做如 下的配置 。
spring. datasource. url=spring . datasource . password=在 DataSourceProperties 类中都有对应的属性存在 。
@ConfigurationProperties(prefix = "spring . datasource" )public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {private String url;private String username ;private String password;}}@lmport 注解引入了两个自动配置类DataSourcePoolMetadataProvidersConfiguration和DataSourcelnitializationConfiguration 。
配置类 DataSourcePoolMetadataProvidersConfiguration 中定义了 3 个静态内部类 , 用于定义3个DataSource的 DataSourcePoolMetadataProvider的初始化条件 。 其中包括tomcat的 DataSource、HikariDataSource 和 BasicDataSource 。
我们以 tomcat 的 DataSource 为例 , 看一下源代码 。
@Configuration(proxyBeanMethods = false)public class DataSourcePoolMetadataProvidersConfiguration {@Configuration( proxyBeanMethods = false)@Condit ional0nClass(org. apache. tomcat . jdbc . pool . DataSource . class)static class TomcatDataSourcePoolMetadataProviderConfiguration {@Beanpublic DataSourcePoolMetadataProvider tomcatPoolDataSourceMetadataProvider() {return (dataSource) -> {org. apache . tomcat. jdbc . pool. DataSource tomcatDataSource = Data-SourceUnwrapper. unwrap(dataSource, org. apache . tomcat . jdbc . pool . DataSource. class);f (tomcatDataSource != nu1l)return new TomcatDataSourcePoolMetadata( tomcatDataSource);return null;}}}}内部类中判断 classpath 是否存在 tomcat 的 DataSource,如果存在 , 则实例化并注册一-个DataSourcePoolMetadataProvider,其中Lambda表达式为DataSourcePoolMeta-dataProvider 的 getDataSourcePoolMetadata 方法的具体实现 。 DataSourcePoolMetadataProvider 的作用是基于 DataSource 提供一个DataSourcePoolMeta-data,该接口只提供了一一个对应的方法 。
@FunctionalInterfacepublic interface DataSourcePoolMet adataProvider//返回一个用于管理 dataSource 的 DataSourcePoolMetadata 实例 , 如果无法处理指定的数据源 , 则返@nullDataSourcePoolMetadata getDataSourcePoolMetadata (DataSource dataSource);}下面我们再来看自动配置代码中 DataSourcePoolMetadataProvider 接口方法的实现逻辑 。
首先 , 通过 DataSourceUnwrapper 的 unwrap 方法获得- 一个 DataSource 数据源;然后判断数据源是否为 null,如果不为 null,则返回一个 TomcatDataSourcePoolMetadata 对象 , 如果为 null,则返回 null 。
DataSourceUnwrapper 类 的 主 要 作 用 是 提 取 被 代 理 或 包 装 在 自 定 义 Wrapper ( 如Delegating-DataSource )中的数据源 。 DataSourceUnwrapper 的 unwrap 方法部分代码实现如下 。
public staticT unwrap(DataSource dataSource, Class target) {//检查 DataSource 是否能够转化为目标对象 , 如果可以转化返回对象if (target . isInstance(dataSource)) {return target . cast(dataSource);/检查包装 Wrapper 是否为 DataSource 的包装类 ,如果是则返回 DataSource, 否则返@nullT unwrapped = safeUnwrap(dataSource, target);if (unwrapped != nu1l) {return unwrapped;//判断 elegatingDataSource 是 否存在if (DELEGATING_ DATA_ SOURCE_ PRESENT) {DataSource targetDataSource = DelegatingDataSourceUnwrapper. getTarget-DataSource(dataSource);if (targetDataSource != null) {//递归调用本方法return unwrap(targetDataSource, target);//代理判断处理if (AopUtils. isAopProxy(dataSource)) {Object proxyTarget = AopProxyUtils . getSingletonTarget (dataSource);if (proxyTarget instanceof DataSource)return unwrap( (DataSource) proxyTarget, target);return null;}