Spring Boot对JDBC的自动配置

一 点睛

通过分析依赖关系,可知spring-boot-starter-data-jpa依赖于spring-boot-starter-jdbc,所以有必要先研究一下Spring Boot对JDBC的支持。

Spring Boot对JDBC做了一些自动配置,源码位置如下:

二 源码分析

1 DataSourceProperties类分析

@ConfigurationProperties(prefix = DataSourceProperties.PREFIX)
public class DataSourceProperties
        implements BeanClassLoaderAware, EnvironmentAware, InitializingBean {

    public static final String PREFIX = "spring.datasource";  //该前缀的属性自动配置DataSource
    ......
}

2 DataSourceTransactionManagerAutoConfiguration类分析

@Configuration
@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
public class DataSourceTransactionManagerAutoConfiguration {

    @Autowired(required = false)
    private DataSource dataSource;

    @Bean
    @ConditionalOnMissingBean(PlatformTransactionManager.class)
    @ConditionalOnBean(DataSource.class)
    public DataSourceTransactionManager transactionManager() {
        return new DataSourceTransactionManager(this.dataSource);
    }

    @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
    @Configuration
    //自动开启了注解事务的支持
    @EnableTransactionManagement
    protected static class TransactionManagementConfiguration {

    }

}

3 JdbcTemplateConfiguration类分析

@Configuration
@Conditional(DataSourceAutoConfiguration.DataSourceAvailableCondition.class)
protected static class JdbcTemplateConfiguration {

    @Autowired(required = false)
    private DataSource dataSource;

    @Bean
    @ConditionalOnMissingBean(JdbcOperations.class)
    //配置了一个JdbcTemplate
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(this.dataSource);
    }

    @Bean
    @ConditionalOnMissingBean(NamedParameterJdbcOperations.class)
    public NamedParameterJdbcTemplate namedParameterJdbcTemplate() {
        return new NamedParameterJdbcTemplate(this.dataSource);
    }
}

4 DataSourceInitializer类分析

//该类提供初始化数据功能
class DataSourceInitializer implements ApplicationListener<DataSourceInitializedEvent> {

    private static final Log logger = LogFactory.getLog(DataSourceInitializer.class);

    @Autowired
    private ConfigurableApplicationContext applicationContext;

    private DataSource dataSource;

    @Autowired
    private DataSourceProperties properties;

    private boolean initialized = false;

    @PostConstruct
    public void init() {
        if (!this.properties.isInitialize()) {
            logger.debug("Initialization disabled (not running DDL scripts)");
            return;
        }
        if (this.applicationContext.getBeanNamesForType(DataSource.class, false,
                false).length > 0) {
            this.dataSource = this.applicationContext.getBean(DataSource.class);
        }
        if (this.dataSource == null) {
            logger.debug("No DataSource found so not initializing");
            return;
        }
        runSchemaScripts();
    }
    
    //放置在类路径下的schema.sql会自动用来初始化表结构
    private void runSchemaScripts() {
        List<Resource> scripts = getScripts(this.properties.getSchema(), "schema");
        if (!scripts.isEmpty()) {
            runScripts(scripts);
            try {
                this.applicationContext
                        .publishEvent(new DataSourceInitializedEvent(this.dataSource));
                // The listener might not be registered yet, so don't rely on it.
                if (!this.initialized) {
                    runDataScripts();
                    this.initialized = true;
                }
            }
            catch (IllegalStateException ex) {
                logger.warn("Could not send event to complete DataSource initialization ("
                        + ex.getMessage() + ")");
            }
        }
    }

    @Override
    public void onApplicationEvent(DataSourceInitializedEvent event) {
        if (!this.properties.isInitialize()) {
            logger.debug("Initialization disabled (not running data scripts)");
            return;
        }
        // NOTE the event can happen more than once and
        // the event datasource is not used here
        if (!this.initialized) {
            runDataScripts();
            this.initialized = true;
        }
    }
    //放置在类路径下的data.sql会自动用来填充表数据
    private void runDataScripts() {
        List<Resource> scripts = getScripts(this.properties.getData(), "data");
        runScripts(scripts);
    }
    //获取执行sql脚本的名称
    private List<Resource> getScripts(String locations, String fallback) {
        if (locations == null) {
            String platform = this.properties.getPlatform();
            locations = "classpath*:" + fallback + "-" + platform + ".sql,";
            locations += "classpath*:" + fallback + ".sql";
        }
        return getResources(locations);
    }

    private List<Resource> getResources(String locations) {
        List<Resource> resources = new ArrayList<Resource>();
        for (String location : StringUtils.commaDelimitedListToStringArray(locations)) {
            try {
                for (Resource resource : this.applicationContext.getResources(location)) {
                    if (resource.exists()) {
                        resources.add(resource);
                    }
                }
            }
            catch (IOException ex) {
                throw new IllegalStateException(
                        "Unable to load resource from " + location, ex);
            }
        }
        return resources;
    }
    //运行脚本列表
    private void runScripts(List<Resource> resources) {
        if (resources.isEmpty()) {
            return;
        }
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.setContinueOnError(this.properties.isContinueOnError());
        populator.setSeparator(this.properties.getSeparator());
        if (this.properties.getSqlScriptEncoding() != null) {
            populator.setSqlScriptEncoding(this.properties.getSqlScriptEncoding().name());
        }
        for (Resource resource : resources) {
            populator.addScript(resource);
        }
        DatabasePopulatorUtils.execute(populator, this.dataSource);
    }

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值