基于Spring Boot的数据库初始化(三)

Java 0 4063

基于Spring Boot的数据库初始化(三)

本篇本文将继续介绍在升级到spring boot version 2.2.0.M3 之后的版本, 该如何沿用之前的思路方法完成数据库的初始化功能。在前一章基于Spring Boot的数据库初始化(二)博文中提到更新版本后抛出会抛出 java.lang.UnsupportedOperationException: null 的错误。这一章就将这个问题解决掉。

了解更新后异常的原因

根本原因是YamlPropertySourceLoader.java类 更新前版本version 2.2.0.M3

public class YamlPropertySourceLoader implements PropertySourceLoader {

	@Override
	public String[] getFileExtensions() {
		return new String[] { "yml", "yaml" };
	}

	@Override
	public List<PropertySource<?>> load(String name, Resource resource)
			throws IOException {
		if (!ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
			throw new IllegalStateException("Attempted to load " + name
					+ " but snakeyaml was not found on the classpath");
		}
		List<Map<String, Object>> loaded = new OriginTrackedYamlLoader(resource).load();
		if (loaded.isEmpty()) {
			return Collections.emptyList();
		}
		List<PropertySource<?>> propertySources = new ArrayList<>(loaded.size());
		for (int i = 0; i < loaded.size(); i++) {
			String documentNumber = (loaded.size() != 1) ? " (document #" + i + ")" : "";
			propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,
					loaded.get(i)));
		}
		return propertySources;
	}

}

更新后版本version 2.2.0.RELEASE

public class YamlPropertySourceLoader implements PropertySourceLoader {

	@Override
	public String[] getFileExtensions() {
		return new String[] { "yml", "yaml" };
	}

	@Override
	public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
		if (!ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
			throw new IllegalStateException(
					"Attempted to load " + name + " but snakeyaml was not found on the classpath");
		}
		List<Map<String, Object>> loaded = new OriginTrackedYamlLoader(resource).load();
		if (loaded.isEmpty()) {
			return Collections.emptyList();
		}
		List<PropertySource<?>> propertySources = new ArrayList<>(loaded.size());
		for (int i = 0; i < loaded.size(); i++) {
			String documentNumber = (loaded.size() != 1) ? " (document #" + i + ")" : "";
			propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,
					Collections.unmodifiableMap(loaded.get(i)), true));
		}
		return propertySources;
	}

}

两个版本间唯一的区别就是以下两行代码

// 2.2.0.M3
propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,
    loaded.get(i)));
// 2.2.0.RELEASE
propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,
    Collections.unmodifiableMap(loaded.get(i)), true));

那很容易想到, 是否可以自定义一个配置文件加载器, 然后复制前一版本的代码就可以了. Spring Boot确实提供了自定义PropertySource Loaders的方法, 但是并没有我预想的那么顺利, 因为YamlPropertySourceLoader.java类中使用的OriginTrackedYamlLoader.java类不是public的所以我们无法直接使用.

解决方法

自定义PropertySourceLoader

Spring Boot会从META-INF/spring.factories文件加载了许多自定义项,以供内部使用. 利用此文件来加载我们自定义的PropertySourceLoader.

org.springframework.boot.env.PropertySourceLoader=\
com.developerchen.core.extension.MyYamlPropertySourceLoader

MyYamlPropertySourceLoader类代码解析

public class MyYamlPropertySourceLoader extends YamlPropertySourceLoader {

    @Override
    public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
        List<PropertySource<?>> propertySources = super.load(name, resource);
        List<PropertySource<?>> newPropertySources = new ArrayList<>(propertySources.size());

        for (PropertySource<?> propertySource : propertySources) {
            if (propertySource instanceof OriginTrackedMapPropertySource) {
                Map<?, ?> source = (Map) propertySource.getSource();
                Map<Object, Object> newSource = new LinkedHashMap<>((int) (source.size() / 0.75 + 1));
                for (Object key : source.keySet()) {
                    Object value = source.get(key);
                    newSource.put(key, value);
                }
                propertySource = new OriginTrackedMapPropertySource(propertySource.getName(),
                        newSource, true);
            }
            newPropertySources.add(propertySource);
        }
        return newPropertySources;
    }

}

这个类重写了YamlPropertySourceLoader类中的load方法, 使用父类中的方法将yml文件解析出来. 然后将内容遍历出来并用LinkedHashMap替换掉原来用Collections.unmodifiableMap方法处理了的Map. 这样就解决了数据库初始化的问题, 希望Spring官方在未来的更新中提供完善实用的数据库初始化功能.

本文采用 知识共享署名4.0国际许可协议进行许可. 本站文章除注明转载/出处外, 均为本站原创或翻译,转载前请务必署名!