springboot版本:2.7.3
有的时候需要在静态工具方法中访问到系统配置的springboot参数:包括application.preperties以及不同的环境或者其他方式import到spring的参数。
springboot的配置文件位置可能是不确定的,有可能在jar中,jar的config中,或者jar的同目录下,或者jar的同目录下的config文件夹中
Spring Boot 中 Environment 中的配置源于多个配置源,有的来自系统环境变量,有的来自命令行参数,有的来自用户配置。Environment 屏蔽了各个配置源间不同的配置获取方式,对外提供统一的调用接口。并且相关配置的优先级已经处理好,我们只需要从Environment中获取最终的数据即可。
所以,只需要在工具类中SpringBootApplicationPropertiesUtil获取到Environment就能获取到相关配置项。
public class SpringBootApplicationPropertiesUtil {private static ConfigurableEnvironment environment;}
获取的方式有很多,比如 实现ApplicationContextAware接口,重写setApplicationContext, 通过ApplicationContext获取Environment。然后把工具类注册到spring。或者把setEnvironment置为static,在spring启动的合适的时候调用,以注入ConfigurableEnvironment。
我希望Environment的注入时机能更早,在它准备完毕的时候就能注入到工具类中,这些在其他Bean初始化的时候就能可以使用SpringBootApplicationPropertiesUtil,而无法担心Environment尚未注入。
所以这里通过SpringApplicationRunListener#environmentPrepared回调注入Environment
public ConfigurableApplicationContext run(String... args) {....//获取 SpringApplicationRunListener 监听器SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//在prepareEnvironment方法中会调用listeners.environmentPrepared(bootstrapContext, environment);ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);......prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);.....return context;}private ConfigurableEnvironment prepareEnvironment(...) {// Create and configure the environmentConfigurableEnvironment environment = getOrCreateEnvironment();configureEnvironment(environment, applicationArguments.getSourceArgs());ConfigurationPropertySources.attach(environment);// 通知监听器,环境准备好, (也是我们需要把environment注入到工具类的时机)listeners.environmentPrepared(bootstrapContext, environment);......return environment;}
如上文代码,springboot在启动的时候,会先准备好ConfigurableEnvironment,然后调用监听器的environmentPrepared方法,做一些回调,这里就是通过这个回调初始化我们的静态工具类。
这里直接用工具类本身实现SpringApplicationRunListener,而不再额外的写一个监听器。
使用方式:在resources/META-INFO/spring.factories中配置此监听器:
org.springframework.boot.SpringApplicationRunListener=cn.xuqiudong.common.util.SpringBootApplicationPropertiesUtil
注意:注入时机比一般的Bean初始化时机更早,但是在EnvironmentPostProcessor之后
package cn.xuqiudong.common.util;import org.apache.commons.lang3.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.ConfigurableBootstrapContext;import org.springframework.boot.SpringApplication;import org.springframework.boot.SpringApplicationRunListener;import org.springframework.core.env.ConfigurableEnvironment;import org.springframework.core.env.MapPropertySource;import org.springframework.core.env.PropertySource;import java.math.BigDecimal;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.stream.Collectors;import java.util.stream.Stream;/*** 描述: 通过ConfigurableEnvironment读取springboot 配置文件中的值* 比一般的Bean初始化时机更早,但是在EnvironmentPostProcessor之后* <p>* 通过SpringApplicationRunListener* 在spring上下文准备好之前,为SpringBootApplicationPropertiesUtil 工具类设置 ConfigurableEnvironment* 在resources/META-INFO/spring.factories中配置此监听器:* org.springframework.boot.SpringApplicationRunListener=cn.xuqiudong.common.util.SpringBootApplicationPropertiesUtil* </p>* @author Vic.xu* @since 2024-04-18 10:33*/public class SpringBootApplicationPropertiesUtil implements SpringApplicationRunListener {private static ConfigurableEnvironment environment;private static final String DELIMITER = ",";private static final Logger LOGGER = LoggerFactory.getLogger(SpringBootApplicationPropertiesUtil.class);/*** 初始化:should declare a public constructor that accepts a {@link SpringApplication}* * instance and a {@code String[]} of arguments.* @see SpringApplicationRunListener*/public SpringBootApplicationPropertiesUtil(SpringApplication application, String[] args) {LOGGER.info("SpringBootApplicationPropertiesUtil initialized as a SpringApplicationRunListener !!!");}/*** 在spring上下文准备好之前,为本工具类设置 ConfigurableEnvironment*/@Overridepublic void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {setEnvironment(environment);}public static void setEnvironment(ConfigurableEnvironment environment) {SpringBootApplicationPropertiesUtil.environment = environment;}/*** 获取 String* @param key key*/public static String getString(String key) {return environment.getProperty(key);}/*** 获取 String* @param key key* @param defaultValue the default value to return if no value is found*/public static String getString(String key, String defaultValue) {return environment.getProperty(key, defaultValue);}/*** 获取 Boolean* @param key key*/public static Boolean getBoolean(String key) {return environment.getProperty(key, Boolean.class);}/*** 获取 Boolean* @param key key* @param defaultValue the default value to return if no value is found*/public static Boolean getBoolean(String key, Boolean defaultValue) {return environment.getProperty(key, Boolean.class, defaultValue);}/*** 获取 Integer* @param key key*/public static Integer getInteger(String key) {return environment.getProperty(key, Integer.class);}/*** 获取 Integer* @param key key* @param defaultValue the default value to return if no value is found*/public static Integer getInteger(String key, Integer defaultValue) {return environment.getProperty(key, Integer.class, defaultValue);}/*** 获取 BigDecimal* @param key key*/public static BigDecimal getBigDecimal(String key) {return environment.getProperty(key, BigDecimal.class);}/*** 获取 BigDecimal* @param key key* @param defaultValue the default value to return if no value is found*/public static BigDecimal getBigDecimal(String key, BigDecimal defaultValue) {return environment.getProperty(key, BigDecimal.class, defaultValue);}/*** 获取 Double* @param key key*/public static Double getDouble(String key) {return environment.getProperty(key, Double.class);}/*** 获取 Double* @param key key* @param defaultValue the default value to return if no value is found*/public static Double getDouble(String key, Double defaultValue) {return environment.getProperty(key, Double.class, defaultValue);}/*** 获取long* @param key key* @param defaultValue the default value to return if no value is found*/public static Long getLong(String key, Long defaultValue) {return environment.getProperty(key, Long.class, defaultValue);}/*** 获取long* @param key key*/public static Long getLong(String key) {return environment.getProperty(key, Long.class);}/*** 获取逗号分隔的字符串为List* @param key key*/public static List<String> getStringAsList(String key) {String property = environment.getProperty(key);if (StringUtils.isBlank(property)) {return new ArrayList<>();}return Stream.of(property.split(DELIMITER)).collect(Collectors.toList());}/*** 获取 Map* (此处不缓存, 兼容以后动态刷新环境变量的情境)* @param prefix key prefix*/public static Map<String, Object> getMapConfig(String prefix) {Map<String, Object> result = new HashMap<>();if (StringUtils.isBlank(prefix)) {return result;}for (PropertySource<?> propertySource : environment.getPropertySources()) {if (propertySource instanceof MapPropertySource) {MapPropertySource mapPropertySource = (MapPropertySource) propertySource;Map<String, Object> sourceMap = mapPropertySource.getSource();for (Map.Entry<String, Object> entry : sourceMap.entrySet()) {String propertyName = entry.getKey();prefix += ".";if (propertyName.startsWith(prefix)) {String keyWithoutPrefix = propertyName.substring(prefix.length());result.put(keyWithoutPrefix, entry.getValue());}}}}return result;}}
2024-04-19
源码地址:lcxm-common-util