设为首页 加入收藏

TOP

SpringBoot 阅读源码之RandomValuePropertySource 是如何工作的(一)
2023-07-25 21:38:15 】 浏览:53
Tags:SpringBoot RandomValuePropertySource 何工作

最近在极客时间上面学习丁雪丰老师的《玩转 Spring 全家桶》,看到一个在application.properties 里面生成随机数的例子,觉得很厉害,带着崇拜的心情去阅读了一下Spring的源码,总算搞清楚了它是怎么工作的,阅读优秀的源代码是一个很不错的学习方式,这篇文章就是记录一下这个学习的过程。

还是先通过示例来进入学习

首先我们建一个springboot的工程,入口程序如下, 就是打印出两个从配置文件中定义的value

@SpringBootApplication
@Slf4j
public class PropertySourceDemoApplication implements ApplicationRunner {
    @Value("${property.demo.test}")
    private String hello;

    @Value("${property.demo.random}")
    private int random_value;
    public static void main(String[] args) {
        SpringApplication.run(PropertySourceDemoApplication.class, args);
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("{} {}", hello, random_value);
    }
}


配置文件 application.properties

property.demo.random=${random.int}
property.demo.test=hello

程序输入出为 "hello -14137621", 这个-14137621就是我们生成的随机数
那么这个功能是怎么在spring-boot实现的呢?

准备阶段

首先我们需要工具类,我们自己可以设计一下,如果我们需要完成这项任务,那么我们需要两个最基本的类,一个是随机数生成类org.springframework.boot.env.RandomValuePropertySource,一个是读取配置文件类 org.springframework.boot.env.PropertiesPropertySourceLoader。我们来看下这两个类的代码。
image
上图是RandomValuePropertySource, 我们可以看到它的getProperty方法就是看name是不是以random开头,是的话就生成随机数返回,这就是我们为什么值为${random.int}

再来看PropertiesPropertySourceLoader

public class PropertiesPropertySourceLoader implements PropertySourceLoader {

	private static final String XML_FILE_EXTENSION = ".xml";

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

	@Override
	public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
		List<Map<String, ?>> properties = loadProperties(resource);
		if (properties.isEmpty()) {
			return Collections.emptyList();
		}
		List<PropertySource<?>> propertySources = new ArrayList<>(properties.size());
		for (int i = 0; i < properties.size(); i++) {
			String documentNumber = (properties.size() != 1) ? " (document #" + i + ")" : "";
			propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,
					Collections.unmodifiableMap(properties.get(i)), true));
		}
		return propertySources;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private List<Map<String, ?>> loadProperties(Resource resource) throws IOException {
		String filename = resource.getFilename();
		List<Map<String, ?>> result = new ArrayList<>();
		if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
			result.add((Map) PropertiesLoaderUtils.loadProperties(resource));
		}
		else {
			List<Document> documents = new OriginTrackedPropertiesLoader(resource).load();
			documents.forEach((document) -> result.add(document.asMap()));
		}
		return result;
	}

}

通过阅读这个代码我们可以看出或者猜测,它就是把后缀名是properties或者xml的文件读到内存中,实际上也是这样的。
有了这两个类,剩下的就是如何把它们组织起来,这是spring强大的地方,也是复杂的地方。
这里不同版本可能代码不一样,但是大同小异吧,我使用的是springboot 3.0.0。
这里把代码的组织结构贴出来
image

image

image

image

image

image

image

image

最后我们可以看到执行了ApplicationListener.onApplicationEvent.
我们打开spring.factories 中看到EnviormentPostProcessorApplicationListener实现了这个接口
image

打开它的代码可以看到
image

最后到了EnvironmentPostProcessor.postPr

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇面试官:如何在千万级数据中查询 .. 下一篇你的项目使用的是哪种配置文件?

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目