一、前言
最近有一个Java后台项目,使用了远程的配置中心(SpringCloudConfig),也就是说配置信息都在远程(一个git上存着),这个Java项目启动时会从远程读取yml等配置信息,然后完成启动。
现在同事想在Util类中写一个静态方法
,用到一个静态变量
(static类型),让静态变量
读取远程yml上配置的值,给类加了@Component
注解,给变量加了@Value
注解,但是发现那个静态变量还是没有值
。
根据spring的实现原理,加了@Component注解后,spring会创建一个类对象放入spring容器;但是@Value注解只能让非静态变量
读取到yml中配置的值,静态变量加上@Value也是没有效果的
。
因此,本人想到了一种简便的实现方式,可以让静态变量也读取到远程yml中配置的值,现总结如下。
二、具体方法(亲测可用)
1.假设application.yml中配置了这样一个值:
settingStr: abc
2.假设写一个Java类,目标是让静态变量获取到yml中配置的值。
//加注解,交给spring管理,spring会new【1个】MyUtil,装入spring容器,使用【myUtil】可以从容器中取出来
@Component
public class MyUtil {
//【目标,让settingStr使用yml中配置的值。】
//这里,静态变量加Value也是没有用的,获取不到yml中配置的值
@Value("settingStr")
public static String settingStr;
//这样写是可以获取到的
@Value("settingStr")
public String ss;
//实际要用这个方法处理某些逻辑
public static String execute(){
//要用到静态变量,值应该是yml中配置的才行
System.out.println(settingStr);
//省略具体步骤
return settingStr;
}
}
●这里,写了一个MyUtil类,想让静态变量settingStr
使用yml
中配置的settingStr
的值。
●注意,ss可以正确使用yml中配置的值,但是静态变量settingStr是获取不到
的。
3.写一个监听器类,当spring容器初始化完成后执行,使用这个监听器类给settingStr赋值即可。
@Component
public class AfterSpringListener implements ApplicationListener<ContextRefreshedEvent>
{
@Override
public void onApplicationEvent(ContextRefreshedEvent event)
{
//从spring容器中拿出spring创建的MyUtil对象
MyUtil myUtil = (MyUtil) event.getApplicationContext().getBean("myUtil");
//sprign容器已经给ss赋值了,现在用ss给static变量赋值
MyUtil.settingStr = myUtil.ss;
}
}
●这里,因为spring容器已经初始化完成了,MyUtil对象已经存在于spring容器了,ss的值也由spring初始化完成了(从yml中读取的);所以现在把ss的值设置给settingStr,就相当于静态变量settingStr使用yml中的值初始化完成了。
4.写一个Controller类自测一下,就可以发现静态变量settingStr使用的确实是yml中配置的值
了。
@RestController
public class TestController {
@ResponseBody
@RequestMapping(value = "/abc")
public JSONObject findAbc(){
JSONObject jsonObject = new JSONObject();
//直接获取测试
jsonObject.put("key", MyUtil.settingStr);
//通过静态方法测试
String str = MyUtil.execute();
System.out.println(str);
return jsonObject;
}
}
三、注意事项
1.静态变量settingStr的值,是在spring容器初始化完成后、自己写的监听器方法执行后、才被赋予的;
因此,只有这个时间点后的操作才能获取到settingStr的值(Controller),这个时间点前获取的话仍然为null。
如果实在想在spring容器初始化前让静态变量获取到yml中的值,那只能自己写个读取yml的方法、提前调用赋值给静态变量了。
<不过本项目的yml在远程,是不能这样实现的。(你这是在为难我spring-_-
)>
2.关于SpringCloudConfig动态刷新的问题,如果远程yml被修改了(yml在git上),那么其它Java后台是可以使用新的yml的,无需其它操作(不用重启项目)。
通过百度发现,当远程配置文件yml被修改后
,其它Java后台会重新加载spring容器
(重新new一个);
因此,假如修改了远程yml中的静态变量的值,就会使spring容器被重新加载,继而重新调用spring容器初始化后的监听方法,也就让静态变量的值刷新为最新的了。
3.据说使用Spring的Bean后置处理器也可以实现,但是感觉用的少、较复杂,在此就不研究怎么用了。
相关文章:
Spring Cloud Config 动态刷新实现机制
https://blog.youkuaiyun.com/woshilijiuyi/article/details/88293782