application.yml
或者application.properties
中配置的属性绑定到某个类对应的属性上@Value
或@ConfigurationProperties
这种方式就不多说了,使用比较简单,但是局限性也比较大,比如只能在容器启动过程中的特定阶段进行绑定,如果容器启动好了或者容器正常运行中,再想去将动态读取到的配置属性绑定到某个对象上,那么@Value
或@ConfigurationProperties
是做不到的 @Value
或@ConfigurationProperties
标识的类上),此时我们需要将properties配置文件里的某些属性读取出来(映射到某个对象上),BeanDefinitionRegistry
+ 动态读取配置文件配置的多个数据源配置】来动态的向容器里注册自定义数据源的bean定义信息,以便spring启动时能将这些自定义的数据源注入容器org.springframework.boot.context.properties.bind.Binder
来进行绑定,但是springboot1.x中并没有这么方便的Binder,所以需要我们自己改造一下比如:在容器已经启动完成并且运行过程中将如下配置绑定到SmartPoolProperties
对象上
# 动态线程池之重试线程池配置
smart.pool.config.executors.retryExecutor.corePoolSize=1
smart.pool.config.executors.retryExecutor.maximumPoolSize=5
smart.pool.config.executors.retryExecutor.queueCapacity=256
smart.pool.config.executors.retryExecutor.keepAliveTime=30
smart.pool.config.executors.retryExecutor.threadNamePrefix=retry-executor
smart.pool.config.executors.retryExecutor.awaitTerminationSeconds=30
smart.pool.config.executors.retryExecutor.rejectedExecutionHandler=AbortPolicy
# 动态线程池之订单线程池配置
smart.pool.config.executors.orderExecutor.corePoolSize=1
smart.pool.config.executors.orderExecutor.maximumPoolSize=5
smart.pool.config.executors.orderExecutor.queueCapacity=256
smart.pool.config.executors.orderExecutor.keepAliveTime=30
smart.pool.config.executors.orderExecutor.threadNamePrefix=order-executor
smart.pool.config.executors.orderExecutor.awaitTerminationSeconds=30
smart.pool.config.executors.orderExecutor.rejectedExecutionHandler=AbortPolicy
# 动态线程池之会员线程池配置
smart.pool.config.executors.customerExecutor.corePoolSize=1
smart.pool.config.executors.customerExecutor.maximumPoolSize=5
smart.pool.config.executors.customerExecutor.queueCapacity=256
smart.pool.config.executors.customerExecutor.keepAliveTime=30
smart.pool.config.executors.customerExecutor.threadNamePrefix=customer-executor
smart.pool.config.executors.customerExecutor.awaitTerminationSeconds=30
smart.pool.config.executors.customerExecutor.rejectedExecutionHandler=AbortPolicy
public class SmartPoolProperties implements InitializingBean {/*** 线程池配置集合*/private Map executors;/*** 配置文件类型(用于刷新线程池配置)** @see ConfigFileTypeEnum*/private String configFileType = ConfigFileTypeEnum.PROPERTIES.getValue();@Overridepublic void afterPropertiesSet() throws Exception {if (Objects.isNull(executors)) {return;}executors.forEach((threadPoolName, properties) -> {String poolName = properties.getThreadPoolName();if (StringUtils.isNotBlank(poolName) && !poolName.equals(threadPoolName)) {throw new SmartPoolExecutorException(String.format("threadPoolName is different, " +"the first is [%s] and the second is [%s]", threadPoolName, poolName));}properties.setThreadPoolName(threadPoolName);});}
}
ThreadpoolProperties
public class ThreadPoolProperties {/*** 核心线程数,默认5*/protected int corePoolSize = 5;/*** 最大线程数,默认20*/protected int maximumPoolSize = 20;/*** 队列容量,默认1024 (一旦确定,禁止更新)*/protected int queueCapacity = 1024;/*** 保活秒数,默认300s*/protected long keepAliveTime = 300;/*** Timeout unit.*/private TimeUnit unit = TimeUnit.SECONDS;/*** 线程池拒绝策略名称,默认 {@link RejectedTypeEnum#CALLER_RUNS_POLICY}*/protected String rejectedExecutionHandler = RejectedTypeEnum.CALLER_RUNS_POLICY.getName();/*** 允许核心线程超时,默认false*/protected boolean allowCoreThreadTimeOut = false;
}
org.springframework.boot.bind.PropertySourcesBinder#bindTo
MapPropertySource
,可以直接使用springboot提供的org.springframework.core.env.MapPropertySource
即可org.springframework.core.env.MapPropertySource
,因此自己拓展了一下 org.springframework.core.env.MapPropertySource
/*** {@link org.springframework.core.env.PropertySource} that reads keys and values from a {@code Map} object.** @author wenpanfeng* @see org.springframework.core.env.PropertiesPropertySource*/
public class MapPropertySource extends EnumerablePropertySource
PropertiesBinder
可以方便的将ConfigurableEnvironment
里的属性按照指定前缀绑定到指定的对象上/*** 属性绑定器** @author wenpanfeng 2022/11/23 10:57*/
@Slf4j
public class PropertiesBinder {private PropertiesBinder() {}/*** 绑定smart pool properties** @param configurableEnvironment configurableEnvironment* @return SmartPoolProperties* @author wenpanfeng 2022/11/23 11:12*/public static SmartPoolProperties bindSmartPoolProperties(ConfigurableEnvironment configurableEnvironment) {return bindProperties(configurableEnvironment, PrefixConst.ExecutorConfig.SMART_POOL_PREFIX, SmartPoolProperties.class);}/*** 绑定properties to smartPoolProperties** @param properties properties* @param smartPoolProperties smartPoolProperties* @author wenpanfeng 2022/11/24 21:15*/public static void bindSmartProperties(Map properties, SmartPoolProperties smartPoolProperties) {bindProperties(properties, PrefixConst.ExecutorConfig.SMART_POOL_PREFIX, smartPoolProperties);}/*** 绑定属性到target** @param properties properties* @param prefix 绑定前缀* @param target 目标对象* @author wenpanfeng 2022/11/24 17:05*/public static void bindProperties(Map properties, String prefix, T target) {try {log.info("------------>>>>>>>>>> start bind properties, prefix is {}, target is {}", prefix, target);MapPropertySource mapPropertySource = new MapPropertySource("PropertiesBinder.bindSmartProperties", properties);MutablePropertySources propertySources = new MutablePropertySources();propertySources.addLast(mapPropertySource);PropertySourcesBinder binder = new PropertySourcesBinder(propertySources);binder.bindTo(prefix, target);log.info("------------>>>>>>>>>> end bind properties, prefix is {}, target is {}", prefix, target);} catch (Exception ex) {log.info("------------>>>>>>>>>> error bind properties, prefix is {}, target is {}", prefix, target);throw new PropertiesBindException(String.format("Bind properties failed, prefix is [%s], target is [%s]", prefix, target));}}/*** 属性绑定** @param configurableEnvironment Environment* @param prefix 属性前缀* @param clazz target clazz* @return T* @author wenpanfeng 2022/11/23 11:04*/public static T bindProperties(ConfigurableEnvironment configurableEnvironment, String prefix, Class clazz) {try {log.info("------------>>>>>>>>>> start bind properties, prefix is {}, clazz is {}", prefix, clazz);PropertySourcesBinder propertySourcesBinder = new PropertySourcesBinder(configurableEnvironment);T instance = clazz.newInstance();propertySourcesBinder.bindTo(prefix, instance);log.info("------------>>>>>>>>>> end bind properties, prefix is {}, clazz is {}", prefix, clazz);return instance;} catch (Exception ex) {log.info("------------>>>>>>>>>> error bind properties, prefix is {}, clazz is {}", prefix, clazz);throw new PropertiesBindException(String.format("Bind properties failed, prefix is [%s], Class is [%s]", prefix, clazz));}}
}
Binder
,直接使用即可,不过多介绍!!!public class PropertiesBinder {private PropertiesBinder() {}public static void bindDtpProperties(Map, Object> properties, DtpProperties dtpProperties) {ConfigurationPropertySource sources = new MapConfigurationPropertySource(properties);Binder binder = new Binder(sources);ResolvableType type = ResolvableType.forClass(DtpProperties.class);Bindable> target = Bindable.of(type).withExistingValue(dtpProperties);binder.bind(MAIN_PROPERTIES_PREFIX, target);}public static void bindDtpProperties(Environment environment, DtpProperties dtpProperties) {Binder binder = Binder.get(environment);ResolvableType type = ResolvableType.forClass(DtpProperties.class);Bindable> target = Bindable.of(type).withExistingValue(dtpProperties);binder.bind(MAIN_PROPERTIES_PREFIX, target);}
}