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配置文件中值更新的时候,我们需要重启服务才能生效。

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值