static变量获取nacos配置文件值
问题背景
最近在将配置中心从apollo迁移到Nacos,涉及的一些变量的获取需要修改,这里遇到的问题是static变量使用@Value注解获取,但这里会报空指针错误,如下:
@Value("${file.server.addr}")
private static String serverAddr;
因为用到serverAddr
变量的地方在一个静态方法里面,改成非静态变量的话改动成本又比较大,所以考虑需要解决这个问题,尝试检查工具类是否交给了Spring管理,在类上添加@Component
或者@Configuration
注解,但这样也是不会生效的,原因就是静态成员变量在类加载时就初始化,而此时Nacos的值还未加载或获取到,它会优先于Spring Bean对象的初始化,所以无法注入进去。
解决方案:
1.通过set方法注入
private static String serverAddr;
@Value("${file.server.addr}")
public void setServerAddr(String sd){
serverAddr = sd;
}
2.通过@PostConstruct
private static String serverAddr;
@Value("${file.server.addr}")
private String sd;
@PostConstruct
public void init(){
serverAddr = sd;
}
@PostConstruct
是Java自带的注解,通常用来执行一些初始化操作,被@PostConstruct
修饰的方法需要为非静态的void()
方法,会在构造函数执行执行之后执行。
3.通过实现InitializingBean接口
@Component
public class MyUtil implements InitializingBean {
private static String serverAddr;
@Value("${file.server.addr}")
private String sd;
@Override
public void afterPropertiesSet() throws Exception {
serverAddr = sd;
}
}
InitializingBean
接口是Spring的一个扩展接口,提供了Bean的初始化方法:afterPropertiesSet
,从名字上也可看出,方法的执行阶段是在bean的属性被设置值之后,常用来修改默认设置的属性。另外它与Bean中的init-method
属性对应的方法功能是一致的,同时它也是在init-method
方法前执行。
上面的一些执行时机如下:
Constructor -> @Autowired -> @PostConstruct->afterPropertiesSet
4.SpringContextUtil获取
1)Config.java
@Component
public class FileConfig{
@Autowired
private ConfigurableApplicationContext configurableApplicationContext;
@Value("${file.server.addr:}")
private String serverAddr;
public String getServerAddr() {
return serverAddr =configurableApplicationContext.getEnvironment().getProperty("file.server.addr");
}
}
2) SpringContextUtil.java
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/**
* 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getContext() {
checkApplicationContext();
return applicationContext;
}
public static Object getBean(String name) throws BeansException{
return applicationContext.getBean(name);
}
private static void checkApplicationContext() {
Assert.notNull(applicationContext,
"applicaitonContext未注入,请在applicationContext.xml中定义SpringContextUtil");
}
}
3)static调用类
public class TestService {
public static void initTest() {
FileConfig config = (FileConfig) SpringContextUtil.getBean("fileConfig");
...
}
}
原来的静态方法里面获取静态变量,可以从Spring容器中的Bean对象获取,变量也封装到了FileConfig类里面,静态方法里面的Bean对象可以通过SpringContextUtil
工具类来获取。
注意:
1.这里@Value("${file.server.addr}")
里面的变量值要确认存在于Nacos配置文件当中并确保格式正确;
2.SpringContextUtil
如果里面applicationContext
有空指针问题,请检查SpringContextUtil
有没有被Spring扫描到;
总结
static方法修饰的静态变量从配置文件中获取,用到的地方还是挺多的,比如在一些工具类当中,通常这些工具类里面的变量是全局的,在很多地方都有调用。这里1/2/3方案都是先将Spring对象中的变量加载完成后,再主动将值赋值给静态变量实现的,因为只加载一次,所以当Nacos配置文件中值更新的时候,我们需要重启服务才能生效。
更多推荐
所有评论(0)