静态工具类读取springboot配置文件:通过ConfigurableEnvironment和SpringApplicationRunListener

文章来源原创   作者:临窗旋墨   发布时间:2024-04-19   阅读:113   标签:源码,springboot 分类:springboot 专题:springboot

静态工具类读取springboot配置文件:通过ConfigurableEnvironment和SpringApplicationRunListener

springboot版本:2.7.3

  1. 有的时候需要在静态工具方法中访问到系统配置的springboot参数:包括application.preperties以及不同的环境或者其他方式import到spring的参数。

  2. springboot的配置文件位置可能是不确定的,有可能在jar中,jar的config中,或者jar的同目录下,或者jar的同目录下的config文件夹中

  3. 所以读取springboot配置文件的工具类无法写死配置文件的目录。
  4. 因此,需要借助springboot去读取这些配置参数。

一 、借助Environment读取参数配置项

Spring Boot 中 Environment 中的配置源于多个配置源,有的来自系统环境变量,有的来自命令行参数,有的来自用户配置。Environment 屏蔽了各个配置源间不同的配置获取方式,对外提供统一的调用接口。并且相关配置的优先级已经处理好,我们只需要从Environment中获取最终的数据即可。

所以,只需要在工具类中SpringBootApplicationPropertiesUtil获取到Environment就能获取到相关配置项

  1. public class SpringBootApplicationPropertiesUtil {
  2. private static ConfigurableEnvironment environment;
  3. }

获取的方式有很多,比如 实现ApplicationContextAware接口,重写setApplicationContext, 通过ApplicationContext获取Environment。然后把工具类注册到spring。或者把setEnvironment置为static,在spring启动的合适的时候调用,以注入ConfigurableEnvironment。

二、借助SpringApplicationRunListener提前注入Environment到工具类

  • 我希望Environment的注入时机能更早,在它准备完毕的时候就能注入到工具类中,这些在其他Bean初始化的时候就能可以使用SpringBootApplicationPropertiesUtil,而无法担心Environment尚未注入。

  • 所以这里通过SpringApplicationRunListener#environmentPrepared回调注入Environment

三、springboot(2.7.3)run部分源码

  1. public ConfigurableApplicationContext run(String... args) {
  2. ....
  3. //获取 SpringApplicationRunListener 监听器
  4. SpringApplicationRunListeners listeners = getRunListeners(args);
  5. listeners.starting(bootstrapContext, this.mainApplicationClass);
  6. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  7. //在prepareEnvironment方法中会调用listeners.environmentPrepared(bootstrapContext, environment);
  8. ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
  9. configureIgnoreBeanInfo(environment);
  10. ......
  11. prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
  12. refreshContext(context);
  13. afterRefresh(context, applicationArguments);
  14. .....
  15. return context;
  16. }
  17. private ConfigurableEnvironment prepareEnvironment(...) {
  18. // Create and configure the environment
  19. ConfigurableEnvironment environment = getOrCreateEnvironment();
  20. configureEnvironment(environment, applicationArguments.getSourceArgs());
  21. ConfigurationPropertySources.attach(environment);
  22. // 通知监听器,环境准备好, (也是我们需要把environment注入到工具类的时机)
  23. listeners.environmentPrepared(bootstrapContext, environment);
  24. ......
  25. return environment;
  26. }

如上文代码,springboot在启动的时候,会先准备好ConfigurableEnvironment,然后调用监听器的environmentPrepared方法,做一些回调,这里就是通过这个回调初始化我们的静态工具类。

SpringBootApplicationPropertiesUtil代码

这里直接用工具类本身实现SpringApplicationRunListener,而不再额外的写一个监听器。

使用方式:在resources/META-INFO/spring.factories中配置此监听器:

org.springframework.boot.SpringApplicationRunListener=cn.xuqiudong.common.util.SpringBootApplicationPropertiesUtil

注意注入时机比一般的Bean初始化时机更早,但是在EnvironmentPostProcessor之后

  1. package cn.xuqiudong.common.util;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.boot.ConfigurableBootstrapContext;
  6. import org.springframework.boot.SpringApplication;
  7. import org.springframework.boot.SpringApplicationRunListener;
  8. import org.springframework.core.env.ConfigurableEnvironment;
  9. import org.springframework.core.env.MapPropertySource;
  10. import org.springframework.core.env.PropertySource;
  11. import java.math.BigDecimal;
  12. import java.util.ArrayList;
  13. import java.util.HashMap;
  14. import java.util.List;
  15. import java.util.Map;
  16. import java.util.stream.Collectors;
  17. import java.util.stream.Stream;
  18. /**
  19. * 描述: 通过ConfigurableEnvironment读取springboot 配置文件中的值
  20. * 比一般的Bean初始化时机更早,但是在EnvironmentPostProcessor之后
  21. * <p>
  22. * 通过SpringApplicationRunListener
  23. * 在spring上下文准备好之前,为SpringBootApplicationPropertiesUtil 工具类设置 ConfigurableEnvironment
  24. * 在resources/META-INFO/spring.factories中配置此监听器:
  25. * org.springframework.boot.SpringApplicationRunListener=cn.xuqiudong.common.util.SpringBootApplicationPropertiesUtil
  26. * </p>
  27. * @author Vic.xu
  28. * @since 2024-04-18 10:33
  29. */
  30. public class SpringBootApplicationPropertiesUtil implements SpringApplicationRunListener {
  31. private static ConfigurableEnvironment environment;
  32. private static final String DELIMITER = ",";
  33. private static final Logger LOGGER = LoggerFactory.getLogger(SpringBootApplicationPropertiesUtil.class);
  34. /**
  35. * 初始化:should declare a public constructor that accepts a {@link SpringApplication}
  36. * * instance and a {@code String[]} of arguments.
  37. * @see SpringApplicationRunListener
  38. */
  39. public SpringBootApplicationPropertiesUtil(SpringApplication application, String[] args) {
  40. LOGGER.info("SpringBootApplicationPropertiesUtil initialized as a SpringApplicationRunListener !!!");
  41. }
  42. /**
  43. * 在spring上下文准备好之前,为本工具类设置 ConfigurableEnvironment
  44. */
  45. @Override
  46. public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
  47. setEnvironment(environment);
  48. }
  49. public static void setEnvironment(ConfigurableEnvironment environment) {
  50. SpringBootApplicationPropertiesUtil.environment = environment;
  51. }
  52. /**
  53. * 获取 String
  54. * @param key key
  55. */
  56. public static String getString(String key) {
  57. return environment.getProperty(key);
  58. }
  59. /**
  60. * 获取 String
  61. * @param key key
  62. * @param defaultValue the default value to return if no value is found
  63. */
  64. public static String getString(String key, String defaultValue) {
  65. return environment.getProperty(key, defaultValue);
  66. }
  67. /**
  68. * 获取 Boolean
  69. * @param key key
  70. */
  71. public static Boolean getBoolean(String key) {
  72. return environment.getProperty(key, Boolean.class);
  73. }
  74. /**
  75. * 获取 Boolean
  76. * @param key key
  77. * @param defaultValue the default value to return if no value is found
  78. */
  79. public static Boolean getBoolean(String key, Boolean defaultValue) {
  80. return environment.getProperty(key, Boolean.class, defaultValue);
  81. }
  82. /**
  83. * 获取 Integer
  84. * @param key key
  85. */
  86. public static Integer getInteger(String key) {
  87. return environment.getProperty(key, Integer.class);
  88. }
  89. /**
  90. * 获取 Integer
  91. * @param key key
  92. * @param defaultValue the default value to return if no value is found
  93. */
  94. public static Integer getInteger(String key, Integer defaultValue) {
  95. return environment.getProperty(key, Integer.class, defaultValue);
  96. }
  97. /**
  98. * 获取 BigDecimal
  99. * @param key key
  100. */
  101. public static BigDecimal getBigDecimal(String key) {
  102. return environment.getProperty(key, BigDecimal.class);
  103. }
  104. /**
  105. * 获取 BigDecimal
  106. * @param key key
  107. * @param defaultValue the default value to return if no value is found
  108. */
  109. public static BigDecimal getBigDecimal(String key, BigDecimal defaultValue) {
  110. return environment.getProperty(key, BigDecimal.class, defaultValue);
  111. }
  112. /**
  113. * 获取 Double
  114. * @param key key
  115. */
  116. public static Double getDouble(String key) {
  117. return environment.getProperty(key, Double.class);
  118. }
  119. /**
  120. * 获取 Double
  121. * @param key key
  122. * @param defaultValue the default value to return if no value is found
  123. */
  124. public static Double getDouble(String key, Double defaultValue) {
  125. return environment.getProperty(key, Double.class, defaultValue);
  126. }
  127. /**
  128. * 获取long
  129. * @param key key
  130. * @param defaultValue the default value to return if no value is found
  131. */
  132. public static Long getLong(String key, Long defaultValue) {
  133. return environment.getProperty(key, Long.class, defaultValue);
  134. }
  135. /**
  136. * 获取long
  137. * @param key key
  138. */
  139. public static Long getLong(String key) {
  140. return environment.getProperty(key, Long.class);
  141. }
  142. /**
  143. * 获取逗号分隔的字符串为List
  144. * @param key key
  145. */
  146. public static List<String> getStringAsList(String key) {
  147. String property = environment.getProperty(key);
  148. if (StringUtils.isBlank(property)) {
  149. return new ArrayList<>();
  150. }
  151. return Stream.of(property.split(DELIMITER)).collect(Collectors.toList());
  152. }
  153. /**
  154. * 获取 Map
  155. * (此处不缓存, 兼容以后动态刷新环境变量的情境)
  156. * @param prefix key prefix
  157. */
  158. public static Map<String, Object> getMapConfig(String prefix) {
  159. Map<String, Object> result = new HashMap<>();
  160. if (StringUtils.isBlank(prefix)) {
  161. return result;
  162. }
  163. for (PropertySource<?> propertySource : environment.getPropertySources()) {
  164. if (propertySource instanceof MapPropertySource) {
  165. MapPropertySource mapPropertySource = (MapPropertySource) propertySource;
  166. Map<String, Object> sourceMap = mapPropertySource.getSource();
  167. for (Map.Entry<String, Object> entry : sourceMap.entrySet()) {
  168. String propertyName = entry.getKey();
  169. prefix += ".";
  170. if (propertyName.startsWith(prefix)) {
  171. String keyWithoutPrefix = propertyName.substring(prefix.length());
  172. result.put(keyWithoutPrefix, entry.getValue());
  173. }
  174. }
  175. }
  176. }
  177. return result;
  178. }
  179. }

2024-04-19

源码地址:lcxm-common-util


发表评论

目录