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 environment
ConfigurableEnvironment 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
*/
@Override
public 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