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

在 afterPropertiesSet 中重点做了 DataSourcelnitializer 的实例化和初始化操作 。 其中DataSourceInitializer 的实例化比较简单 , 就是根据数据源、配置属性和 ApplicationContext创建了一个对象 , 并将对象赋值给 DataSourcelnitializerlnvoker 的属性 , 具体实现如下 。
private DataSourceInitializer getDataSourceInitializer() {if (this.dataSourceInitializer == null;DataSource ds = this . dataSource . getIfUnique();this. dataSourceInitializer = new DataSourceInitializer(ds, this. properties ,this. applicationContext);return this . dataSourceInitializer;}完成了 DataSourcelnitializer 的初始化 , 后续的操作便是调用其提供的方法进行初始化操作 。
比如上面代码中调用 createSchema 方法来执行 DDL 语句(schema-* .sql)就是进行初始化操作 。
值得注意的是 , afterPropertiesSet 方 法中还调用了 initialize 方法,initialize 方法中首先发布了一个 DataSourceSchemaCreatedEvent 事件 。 然后 , 为了防止在发布事件时对应的监听并未注册 , 在发布完事件之后 , 主动做了监听事件中要做的事 。
而对应的监听事件 , 同样定义在 DataSourcelnitializerlnvoker 类中 , 上面我们已经得知它实现了 ApplicationListener 接口 , 监听的便是上面发布的事件 。 onApplicationEvent 方法中的实现与 initialize 方法的实现基本相同(除了发布事件操作) 。
@Overridepublic void onApplicationEvent (DataSourceSchemaCreatedEvent event) {//事件可能发生多次 , 这里未使用数据源事件DataSourceInitializer initializer = getDataSourceInitializer();if (!this. initialized this. initialized = true;}这里稍微拓展一下 DataSourcelnitializer 的两个方法 createSchema 和 initSchema,先看源代码 。
boolean createSchema() {List scripts = getScripts("spring . datasource . schema", this. properties.getSchema(), "schema");if (!scripts. isEmpty()) {if (lisEnabled()) {"Initialization disabled (not running DDL scripts)");return false;String username = this . properties . getSchemaUsername() ;String password = this . properties . getSchemaPassword();runScripts(scripts, username, password);return !scripts. isEmpty();void initSchema() {Listscripts = getScripts("spring. datasource . data", this . propergetData(), "data");//省略部分与 createSchema 方法-致createSchema 方法和 initSchema 方法都是获取指定位置或类路径中的 SQL (.sq) 文件 , 然后再获得用户名和密码 , 最后执行 SQL 文件中的脚本 。
这两个方法不同之处在于:createSchema 常用于初始化建表语句;
initSchema 常用于插入数据及更新数据操作 。
在方法中也可以看到 , 可在 application.properties 文件 中进行如下配置来指定其 SQL 文件位置 。
spring . datasource . schema=classpath:schema -my-mysq1.sqlspring . datasource . data=http://kandian.youth.cn/index/classpath:data-my-mysql . sql也 就 是 说,可 以 通 过 DataSourcelnitializationConfiguration 引 入 的DataSourcelnitializer-Invoker 来完成数据库相关的初始化操作 。
下面我们再看 DataSourcelnitializationConfiguration 引入的另外-一个内部类 Registrar,这也是该自动配置类唯一的代码实现 。
static class Registrar implements ImportBeanDefinitionRegistrar {private static final String BEAN NAME = "dataSourceInitializerPostProcessor" ;@Overridepublic void registerBeanDefinit ions (Annotat ionMetadata importingClassMetaata , BeanDefinitionRegistry registry) {if (!registry. containsBeanDefinition(BEAN NAME)) {GenericBeanDefinition beanDefinition = new GenericBeanDefinition();beanDefinition. setBeanClass (DataSourceInitializerPostProcessor .class)beanDef inition. setRole(BeanDef inition. ROLE_ INFRASTRUCTURE);beanDefinition. setSynthetic(true);registry. registerBeanDefinition(BEAN_ NAME, beanDefinition);}}}内 部 类 Registrar 通 过 实 现 ImportBeanDefinitionRegistrar 接 口 来 完 成DataSourcelnitiali-zerPostProcessor 的注册 。 关于通过 ImportBeanDefinitionRegistrar 动态注入 Bean 的具体使用方法 , 我们在上一章节中已经讲过 , 这里不再赘述 , 下面主要看 一下实现逻辑 。
在 registerBeanDefinitions 方法中首先判断名称为 dataSourcelnitializerPostProcessor 的Bean 是否已经被注册 。 如果未被注册,则通过创建 GenericBeanDefinition 对象封装需要动态创建 Bean 的信息 , 然后通过 BeanDefinitionRegistry 进行注册 。
需要注意的是 , 这里设 置 GenericBeanDefinition 的 synthetic 属性为 true ,这是因为不需要对此对象进行后续处理 , 同时也避免 Bean 的级联初始化 。
最 后 再 看 看 这 里 注 册 的 DataSourcelnitializerPostProcessor 的 作 用。它 实 现 了BeanPost-Processor 接口 , 用于确保 DataSource 尽快初始化 DataSourcelnitializer.class DataSourceInitializerPostProcessor implements BeanPostProcessor, Orde