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

可以看出 unwrap 方法支持以下形式的检查 。
.直接检查对象与目标是否符合 。
.包装类的检查(DataSource 本身继承了 Wrapper 接口) 。
.判断 DelegatingDataSource 类型的数据源是否存在 , 如果存在则递归调用 umwrap 方法 。
.检查 DataSource 是否被代理的对象 。
如果符合上面检查条件(按照先后顺序) , 则根据不同的情况通过不同的方式获得DataSource 对象并返回 。
当获取 DataSource 对象之后便直接创建 TomcatDataSourcePoolMetadata 类的对象 , 该类是针对 Tomcat 数据源的 DataSourcePoolMetadata 具体实现的 。
在创建对象时会将传入的 DataSource 对象赋值给 TomcatDataSourcePoolMetadata 的抽象父类 AbstractDataSourcePoolMetadata 的成员变量 。
public abstract class AbstractDataSourcePoolMetadata针对 DataSourcePoolMetadata 接口方法的具体实现 , 都是围绕着 DataSource 对象中存储的数据源信息展开的 。
DataSourcePoolMetadata 接口提供了大多数数据库都提供的元数据的方法定义 。
public interface DataSourcePoolMetadata {//返回当前数据库连接他的情况 , 返回值在 0 至 1 之间(如果连接他没有限制 , 值为-1)//返回值 1 表示:已分配最大连接数//返回值 0 表示:当前没 有连接处于活跃犹态//返回值- 1 表示:可以分配的连接数没有限制//返回 null 表示:当前数据源不提供必要信息进行计算Float getUsage();//返回当前已分配的活跃连接数 , 返回 null, 则表示该信息不可用Integer getActive();//返回同时可分配的最大活跃连接数 , 返@-1 表示不限制 , 返@null 表示该信息不可用Integer getMax();//返回连接地中最小空闲连接数 , 返@null 表示该信息不可用Integer getMin();//返回查询以验证连接是否有效 , 返@null 表示该信息不可用String getValidat ionQuery();连接他创建的连接的默认自动提交状态 。 如果未将其值没为 null,则默认采用 JDBC 驱动//如果设置为 null, 则方法 java. sql . Connect ion. setAutoCommit(boolean)将不会被调用Boolean getDefaultAutoCommit();}以 DataSourcePoolMetadata 的 getUsage 方法为例 , 我们看一下具体实现方式 。 该方法在其子类 AbstractDataSourcePoolMetadata 中实现 。
@Overridepublic Float getUsage() {Integer maxSize = getMax();Integer currentSize = getActive();//数据源不支持该信息if (maxSize == null|I currentSize == nu1l) {return null;//分配连接没有限制if (maxSize < 0) {return -1F;//当前没有活跃连接if (currentSize == 0) {return OF ;/计算 currentSize maxSize 比值return (float) currentSize / (float) maxSize;}getUsage 方法的实现逻辑很清晰 , 首先通过接口中其他方法来获取数据并进行判断 。 如果获取 maxSize 或 currentSize 为 null, 说明该数据源不支持该信息 。 如果 maxSize 小于 0 , 则表示分配连接没有限制;如果 currentSize 等 于 0 , 则表示当前没有活跃连接;其他情况则计算 currentSize 和 maxSize 比值 。
还是上面提到的 , 这些信息源于构建 NatoCaiirnnDnlMntodnto 传入的 DataSource 。
讲解完了 DataSourcePoolMetadataProvidersConfiguration , 下面再看另外-个引入的配置类 DataSourcelnitializationConfiguration,它主要的功能是配置数据源的初始化 。
DataSourcelnitializationConfiguration 同样分两部分:注解引入和内部实现 。
@Configuration(proxyBeanMethods = false)@Import({ DataSourceInitializerInvoker . class, DataSourceInitializationConfiration. Registrar .class })class DataSourceInitializat ionConfiguration {}首 先 看 引 入 的 DataSourcelnitializerlnvoker, 该 类 实 现 了 ApplicationListener 接 口 和Initiali-zingBean 接口 , 也就是说 , 它同时具有事件监听和执行自定义初始化的功能 。
class DataSourceInitializer Invoker implements ApplicationL istener , InitializingBeanDataSourceInitializer Invoker (objectProvider dataSource, DataSProperties properties,ApplicationContext applicationContext) {this . dataSource = dataSource;this . properties = properties;this . applicationContext = applicat ionContext;}DataSourcelnitializerInvoker 构 造 方 法 被 调 用 时 会 传 入 数 据 源 、 数 据 源 配 置 和Application-Context 信息 , 并赋值给对应的属性 。
由于 DataSourcelnitializerlnvoker 实现了 InitializingBean 接口 , 当 BeanFactory 设置完属性之后 , 会调用 afterPropertiesSet 方法来完成自定义操作 。
@Overridepublic void afterPropertiesSet() {//获取 DataSourceInitializer, 基 FDataSourceProperties 初始化 DataSourceDataSourceInitializer initializer = getDataSourceInitializer();if (initializer != null) {//执行 DDL 语句(schema-*. sql)boolean schemaCreated = tisaorcntiieri cretschema();// 初始化操作initialize(initializer);private void initialize(DataSourceInitializer initializer) {this.applicationContext.publishEvent(new DataSourceSchemaCreatedEvent(initializer.getDataSource()));// 此时 , 监昕器可能尚未注册 , 不能完全依赖 , 因此主动澜用if (!this.initialized)this . dataSourceInitializer. initSchema();this.initialized = true;} catch (IllegalStateException ex) {}