如何将application.properties中的值赋给静态变量?

dan*_*emp 23 java spring spring-boot

我正在使用Spring MVC.我有一个UserService带有@Service很多静态变量的类注释.我想用application.properties文件中的值来实例化它们.

例如,在application.properties中我有: SVN_URL = http://some.url/repositories

然后在课堂上有: @Value("${SVN_URL}") private static String SVN_URL

我明白了 Instantiation of bean failed; nested exception is java.lang.ExceptionInInitializerError

我也试过了 @Autowired private static Environment env;

然后: private static String SVN_URL=env.getProperty("SVN_URL");

它给出了同样的错误.

Szy*_*iak 44

想想你的问题一秒钟.您不必application.properties在静态字段中保留任何属性.帕特里克建议的"解决方法"非常脏:

  • 您不知道何时修改此静态字段
  • 你不知道哪个线程修改它的值
  • 任何时候任何线程都可以改变这个静态字段的值,你就搞砸了
  • 初始化私有静态字段对我来说毫无意义

请记住,当您通过@Service注释控制bean时,您将其创建委托给Spring容器.Spring通过仅创建一个在整个应用程序中共享的bean来控制此bean生命周期(当然,您可以更改此行为,但我在此处引用默认行为).在这种情况下,任何静态字段都没有意义 - Spring确保只有一个实例UserService.并且您得到了您所描述的错误,因为静态字段初始化在Spring容器启动之前发生了许多处理器周期.在这里,您可以找到有关何时初始化静态字段的更多信息.

建议

做这样的事情要好得多:

@Service
public class UserService {
    private final String svnUrl;

    @Autowired
    public UserService(@Value("${SVN_URL}") String svnUrl) {
        this.svnUrl = svnUrl;
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法更好,原因如下:

  • 构造函数注入直接描述初始化对象所需的值
  • final field表示在构造函数调用中初始化后,该值不会被更改(您是线程安全的)

运用 @ConfigurationProperties

还有另一种方法可以将多个属性加载到单个类中.它需要为要加载到配置类的所有值使用前缀.考虑以下示例:

@ConfigurationProperties(prefix = "test")
public class TestProperties {

    private String svnUrl;

    private int somePort;

    // ... getters and setters
}
Run Code Online (Sandbox Code Playgroud)

Spring将处理TestProperties类初始化(它将创建一个testPropertiesbean),您可以将此对象注入Spring容器初始化的任何其他bean.以下是示例application.properties文件的样子:

test.svnUrl=https://svn.localhost.com/repo/
test.somePort=8080
Run Code Online (Sandbox Code Playgroud)

Baeldung 在他的博客上创建了关于这个主题精彩帖子,我建议阅读它以获取更多信息.

替代方案

如果你需要以某种方式在静态上下文中使用值,最好定义一些带有public static final字段的公共类- 这些值将在类加载器加载此类时实例化,并且在应用程序生命周期中不会被修改.唯一的问题是你无法从Spring的application.properties文件加载这些值,你必须直接在代码中维护它们(或者你可以实现一些从属性文件中加载这些常量值的类,但这听起来如此详细说明你要解决的问题).


Pat*_*ick 10

Spring不允许将值注入静态变量.

解决方法是创建一个非静态setter,将您的值赋值给静态变量:

@Service
public class UserService {

    private static String SVN_URL;

    @Value("${SVN_URL}")
    public void setSvnUrl(String svnUrl) {
        SVN_URL = svnUrl;
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 从非静态方法更新静态非最终字段是一个问题. (3认同)
  • 所以没有简单的方法可以用属性文件中的值初始化多个静态变量? (2认同)

Jal*_*mar 7

不允许在静态成员函数中访问 application.properties,但这里有一个解决方法,

应用程序属性

server.ip = 127.0.0.1
Run Code Online (Sandbox Code Playgroud)

属性提取器.java

public class PropertiesExtractor {
     private static Properties properties;
     static {
        properties = new Properties();
        URL url = new PropertiesExtractor().getClass().getClassLoader().getResource("application.properties");
        try{
            properties.load(new FileInputStream(url.getPath()));
           } catch (FileNotFoundException e) {
                e.printStackTrace();
           }
        }

        public static String getProperty(String key){
            return properties.getProperty(key);
        }
}
Run Code Online (Sandbox Code Playgroud)

主类

public class Main {
    private static PropertiesExtractor propertiesExtractor;
    static{
         try {
             propertiesExtractor = new PropertiesExtractor();
         } catch (UnknownHostException e) {
               e.printStackTrace();
           }
    }

    public static getServerIP(){
        System.out.println(propertiesExtractor.getProperty("server.ip")
    }
}
Run Code Online (Sandbox Code Playgroud)