这是我自己基于Environment对象封装的一个配置工程工具类,旨在解决配置在java代码层面的灵活性使用问题!
1. ConfigFactory类基本功能介绍
-
String getString(String key)
根据配置键获取对应String值。 -
Integer getInteger(String key)
根据配置键获取对应Integer类型值。 -
Long getLong(String key)
根据配置键获取对应Long类型值。 -
Boolean getBoolean(String key)
根据配置键获取对应Boolean类型值。 -
T extract(String prefix, Class type)
根据前缀和类类型,提取以配置前缀为目前的配置封装成type对象类型。 -
BindResult bind(String prefix, Class type)
根据前缀和类类型,提取将指定配置前缀开头的配置参数,封装到type对象类型中。 -
BindResult bind(String prefix, T target)
根据前缀和目标对象,提取将指定配置前缀开头的配置参数,封装到taget目标对象中。 -
BindResult bind(String prefix, Bindable target)
根据前缀和可绑定结构,提取将指定配置前缀开头的配置参数,封装到taget目标可绑定结构中。
2. ConfigFactory源码
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
/**
* <pre>Spring配置工厂,解决在无法注入的代码块中,获取指定键对应的配置</pre>
* @author lilinhai
* @since 2019-11-16 20:08
* @version V1.0
*/
public class ConfigFactory
{
private static Environment environment;
private static Binder binder;
/**
* <p>Set Method : environment Environment</p>
* @param environment
*/
public static void setEnvironment(Environment environment)
{
Assert.notNull(environment, "environment can't be null.");
ConfigFactory.environment = environment;
binder = Binder.get(environment);
}
public static String getString(String key)
{
check(key);
return environment.getProperty(key, String.class);
}
public static Integer getInteger(String key)
{
check(key);
return environment.getProperty(key, Integer.class);
}
public static Long getLong(String key)
{
check(key);
return environment.getProperty(key, Long.class);
}
public static Boolean getBoolean(String key)
{
check(key);
return environment.getProperty(key, Boolean.class, false);
}
/**
* 根据prefix从配置中提取对象
* @author sinhy
* @since 2021-12-11 23:00
* @param <T>
* @param prefix
* @param type
* @return T
*/
public static <T> T extract(String prefix, Class<T> type)
{
BindResult<T> br = bind(prefix, type);
return br.isBound() ? br.get() : null;
}
/**
* 根据prefix从配置中提取对象
* @author sinhy
* @since 2021-12-11 23:00
* @param <T>
* @param prefix
* @param type
* @return T
*/
public static <T> BindResult<T> bind(String prefix, Class<T> type)
{
check(prefix);
return binder.bind(prefix, type);
}
/**
* 绑定
* @author sinhy
* @since 2022-06-15 22:20
* @param <T>
* @param prefix
* @param target
* @return BindResult<T>
*/
public static <T> BindResult<T> bind(String prefix, Bindable<T> target)
{
check(prefix);
return binder.bind(prefix, target);
}
/**
* 绑定
* @author sinhy
* @since 2022-06-15 22:20
* @param <T>
* @param prefix
* @param target
* @return BindResult<T>
*/
public static <T> BindResult<T> bind(String prefix, T target)
{
return bind(prefix, Bindable.ofInstance(target));
}
/**
* <p>Get Method : environment Environment</p>
* @return environment
*/
public static Environment getEnvironment()
{
return environment;
}
private static void check(String key)
{
Assert.notNull(environment, "'environment' must not be null.");
Assert.notNull(key, "'key' must not be null.");
}
}
3. ConfigFactory对象初始化
ConfigFactory对象需要初始化后才能正常使用,直接在应用启动更早的地方调用setEnvironment即可完成初始化,如下代码案例中是在EnvironmentPostProcessor的自定义实现中完成ConfigFactory的初始化, EnvironmentPostProcessor是springboot应用启动时较先加载的一个配置组件。通过它去初始化ConfigFactory,可以让ConfigFactory最早得到初始化,以至于在各个地方调用不会出错!
/**
* 自定义EnvironmentPostProcessor
*/
public class ApplicationEnvironmentPostProcessor implements EnvironmentPostProcessor
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application)
{
ConfigFactory.setEnvironment(environment);
}
}
4. extract(String prefix, Class type)使用
在开发中经常遇到,或是非常很重要一个功能,比如在spring容器还未启动完成时,需要实例化某些配置,以进行必要的初始化设置。
今天给大家介绍一个在spring容器启动阶段,有时候需要用到类似 @ConfigurationProperties 用法的场景去初始化一些功能设置。
ConfigFactory.extract即可实现类似 @ConfigurationProperties 的配置注入封装的功能,即提取指定前缀的配置,封装成一个java对象。如下这段代码,需要在应用启动时,根据配置初始化系统的默认Locale和时区。
案例源码
ApplicationConfigProperties applicationProperties = ConfigFactory.extract("spring.application", ApplicationConfigProperties.class);
if (applicationProperties != null)
{
if (!ObjectUtils.isEmpty(applicationProperties.getDefaultLocale()))
{
Locale.setDefault(applicationProperties.getDefaultLocale());
}
if (!ObjectUtils.isEmpty(applicationProperties.getDefaultTimeZone()))
{
TimeZone.setDefault(applicationProperties.getDefaultTimeZone());
}
}
场景分析
这段代码看似简洁,但如果按平常的做法,肯定是先读取配置,然后转换成相应的Locale和TimeZone对象,如果涉及字段繁多的,使用将变得过于繁杂,使用ConfigFactory.extract后,可以瞬间简化操作。
5. bind(String prefix, T target)函数使用
HikariDataSource master = createDataSource(properties, HikariDataSource.class);
ConfigFactory.bind(HIKARI_PREFIX, master);
// 你可以操作master对象的属性了
...
System.out.println(master.getDriverClassName())
6. bind(String prefix, Bindable target)函数使用
以下代码是用于自定义封装从数据库节点列表的真实案例代码:
// 调用 bind(String prefix, Bindable<T> target) 将从节点列表封装成BindResult<List<Properties>>类型
BindResult<List<Properties>> ml = ConfigFactory.bind(SLAVE_PREFIX, Bindable.listOf(Properties.class));
if (ObjectUtils.isEmpty(ml))
{
throw new RuntimeException("从库若是配置了spring.datasource.slaves,则不能为空!");
}
// 从BindResult<List<Properties>>中获取List<DataSource>对象
List<DataSource> slaveDataSources = new ArrayList<>(ml.get().size());
for (Properties slave : ml.get())
{
String username = slave.getProperty("username");
String password = slave.getProperty("password");
String url = slave.getProperty("url");
Assert.notNull(username, "从库用户名不能为空");
Assert.notNull(password, "从库密码不能为空");
Assert.notNull(url, "从库URL不能为空");
DruidDataSource slaveDataSource = createDataSource(properties, DruidDataSource.class);
slaveDataSource.setUsername(username);
slaveDataSource.setPassword(password);
slaveDataSource.setUrl(url);
ConfigFactory.bind(DRUID_PREFIX, slaveDataSource);
slaveDataSource.setDefaultAutoCommit(true);
slaveDataSource.setName("slave-node");
slaveDataSource.init();
slaveDataSources.add(slaveDataSource);
}
7. 总结
以上就是有关ConfigFactory配置工厂类的使用,从初始化,到每个api的介绍。在项目架构设计中经常或多或少需要用到自定义配置组件,此时ConfigFactory类带给配置的灵活性可以体现出来!