Spring动态替换Properties配置变量
Spring动态替换Properties配置变量
有如下需求,在Spring启动的时候,我们需要修改某个指定的配置的值,从而达到动态加载变量的效果:
@Value("${destination}")
public String destination;
1.实现方法有如下:
- 在对应的Spring Bean实例化之后,通过反射动态的修改实例的参数值
- 动态的修改PropertySource
public interface HelloService {/**
* say hello
*/
void sayHello();
}@Service
public class HelloServiceImpl implements HelloService{@Value("${destination}")
private String destination;
@Override
public void sayHello() {
System.out.println("Hello, let us go to " + destination);
}
}
第一种方法实现
方式1:
定义一个应用事件,监听应用上下文刷新事件,然后我们可以通过这个事件拿到ApplicationContext上下文,进而去获取对应的SpringBean,然后进行反射赋值操作。
public class LocalApplicationListener implements ApplicationListener {@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Object helloService = event.getApplicationContext().getBean(HelloService.class);
if (helloService instanceof HelloServiceImpl) {
try {
Field field = HelloServiceImpl.class.getDeclaredField("destination");
field.setAccessible(true);
ReflectionUtils.setField(field, helloService, "广东深圳");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
}
有了这个监听事件,我们需要把这个监听器添加到Spring的监听器集合中,可以通过启动类的启动方法进行添加:
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {
SpringApplication app = new SpringApplication(DemoApplication.class);
app.addListeners(new LocalApplicationListener());
app.run(args);
}
}
方式2:
定义一个类实现BeanPostProcessor接口,在接口中进行反射操作。BeanPostProcessor是Spring提供的一个Bean扩展接口,可以通过该接口实现一些Bean创建之前和创建之后的操作。
@Component
public class LocalBeanProcessor implements BeanPostProcessor {@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof HelloServiceImpl) {
try {
Field field = HelloServiceImpl.class.getDeclaredField("destination");
field.setAccessible(true);
ReflectionUtils.setField(field, bean, "广东广州");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
return bean;
}
}
第二种实现方法:
通过了解Spring的加载流程,我们得知Spring在上下文准备完毕(配置信息解析完毕并创建好了应用上下文)之后,会调用推送一个
ApplicationEnvironmentPreparedEvent
,从这个事件中,我们可以获取到ConfigurableEnvironment
对象,而ConfigurableEnvironment
对象可以获取到MutablePropertySources
。对于MutablePropertySources
,它包含了Spring的所有 的配置信息,包括我们启动应用的application.properties文件的配置信息。具体代码如下:public class LocalEnvironmentPrepareEventListener implements ApplicationListener {@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
MutablePropertySources propertySources = event.getEnvironment().getPropertySources();
for (PropertySource> propertySource : propertySources) {
boolean applicationConfig = propertySource.getName().contains("applicationConfig");
if (!applicationConfig) {
continue;
}
Object property = propertySource.getProperty("destination");
Map source = (Map) propertySource.getSource();
OriginTrackedValue originTrackedValue = https://www.it610.com/article/source.get("destination");
OriginTrackedValue newOriginTrackedValue = https://www.it610.com/article/OriginTrackedValue.of("中国香港", originTrackedValue.getOrigin());
source.put("destination", newOriginTrackedValue);
System.out.println(property);
}
}
}
同样的我们需要把该监听器添加到Spring中:
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {
SpringApplication app = new SpringApplication(DemoApplication.class);
app.addListeners(new LocalEnvironmentPrepareEventListener());
app.run(args);
}
}
知名的分布式配置管理工具
Apollo
就是通过反射来实现配置参数的动态修改的,Apollo
实现了BeanPostProcessor接口,这样它就可以把所有的Bean和@Value的key的关系保存起来,类似于Map>,当配置中心的配置被改动的时候,就发一个通知给对应的服务,然后由服务自己去拉取配置参数,重新赋值。推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- 动态组件与v-once指令
- spring|spring boot项目启动websocket
- Spring|Spring Boot 整合 Activiti6.0.0
- Spring集成|Spring集成 Mina
- springboot使用redis缓存
- Spring|Spring 框架之 AOP 原理剖析已经出炉!!!预定的童鞋可以识别下发二维码去看了