Skip to content

Spring 如何将配置文件中的值保存到静态字段

🏷️ Spring Boot

需求是 在实例化一个对象时,将某个字段的值默认初始化为配置文件中的配置项
使用到了 @Component@Resource@PostConstruct 三个注解。

首先按照需求增加配置项。

application.yml

yaml
# Service
service:
  settings:
    name: SampleService

再增加对应的配置类,在类上使用 @Component 注解,在字段的 set 方法上使用 @Value 注解注入配置文件中对应的配置项值。

ServiceSettings.java

java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 服务配置类
 */
@Component
public class ServiceSettings {
    /**
     * 服务名
     */
    private String name;

    /**
     * 服务名
     */
    public String getName() {
        return name;
    }

    @Value("${service.settings.name}")
    public void setName(String name) {
        this.name = name;
    }
}

在模型类上使用 @Component 注解,在私有字段上使用 @Resource 注解注入配置类的实例,另外使用 @PostConstruct 注解为静态的配置类字段赋值。

从 Java EE5 规范开始,Servlet 增加了两个影响 Servlet 生命周期的注解(Annotation):@PostConstruct@PreDestroy。这两个注解被用来修饰一个非静态的 void 方法.而且这个方法不能有抛出异常声明。

@PostConstruct 说明
@PostConstruct 修饰的方法会在服务器加载 Servlet 的时候运行,并且只会被服务器调用一次,类似于 Servlet 的 init() 方法。被 @PostConstruct 修饰的方法会在构造函数之后,Servlet 的 init() 方法之前运行。

摘自:java 开发之@PostConstruct 和@PreDestroy 注解

SampleEntity.java

java
import com.octopus.middle.common.settings.ServiceSettings;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

@Component
public class SampleEntity {
    @Resource
    private ServiceSettings initServiceSettings;

    private static ServiceSettings serviceSettings;

    @PostConstruct
    public void init() {
        serviceSettings = initServiceSettings;
    }

    /**
     * 服务名
     */
    private String serviceName = serviceSettings != null ? serviceSettings.getName() : null;

    /**
     * 服务名
     */
    public String getServiceName() {
        return serviceName;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }
}

在执行 @PostConstruct 方法前会先实例化 SampleEntity 类,此时 initServiceSettingsserviceSettings 均为 null

实例化之后再调用实例方法 init(),此时 initServiceSettings 有值,serviceSettings 为 null。

在此方法中将使用 @Resource 注解注入的字段(initServiceSettings)值赋给静态变量(serviceSettings),这样就可以在之后的处理中直接使用了。

之后在代码中通过 new 关键字创建实例 (new SampleEntity()) 时,serviceName 字段就可以直接获取到配置文件中的值了。

如果模型组件不在同一个模块中,需要使用 @ComponentScan 注解扫描组件。示例如下:

java
@ComponentScan(basePackages = { "com.xxxx.xxx.common" })
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

参考

  1. Springboot 静态资源类里静态属性注入
  2. java 开发之@PostConstruct 和@PreDestroy 注解