Java 如何将 application.properties 中的值分配给静态变量?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45192373/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:53:10  来源:igfitidea点击:

How to assign a value from application.properties to a static variable?

javaspringspring-boot

提问by dannemp

I am using Spring MVC. I have a UserServiceclass annotated with @Servicethat has a lot of static variables. I would like to instantiate them with values from the application.properties file.

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

For example in application.properties I have: SVN_URL = http://some.url/repositories

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

Then in the class there is: @Value("${SVN_URL}") private static String SVN_URL

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

I get the Instantiation of bean failed; nested exception is java.lang.ExceptionInInitializerError

我得到 Instantiation of bean failed; nested exception is java.lang.ExceptionInInitializerError

I have also tried @Autowired private static Environment env;

我也试过 @Autowired private static Environment env;

And then: private static String SVN_URL=env.getProperty("SVN_URL");

进而: private static String SVN_URL=env.getProperty("SVN_URL");

It gives the same error.

它给出了同样的错误。

采纳答案by Szymon Stepniak

Think about your problem for a second. You don't have to keep any properties from application.propertiesin static fields. The "workaround" suggested by Patrick is very dirty:

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

  • you have no idea when this static field is modified
  • you don't know which thread modifies it's value
  • any thread at any time can change value of this static field and you are screwed
  • initializing private static field that way has no sense to me
  • 你不知道这个静态字段何时被修改
  • 你不知道哪个线程修改了它的值
  • 任何线程在任何时候都可以改变这个静态字段的值,你就完蛋了
  • 以这种方式初始化私有静态字段对我来说没有意义

Keep in mind that when you have bean controlled by @Serviceannotation you delegate its creation to Spring container. Spring controls this bean lifecycle by creating only one bean that is shared across the whole application (of course you can change this behavior, but I refer to a default one here). In this case any static field has no sense - Spring makes sure that there is only one instance of UserService. And you get the error you have described, because static fields initialization happens many processor-cycles before Spring containers starts up. Here you can find more about when static fields are initialized.

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

Suggestion

建议

It would be much better to do something like this:

做这样的事情会好得多:

@Service
public class UserService {
    private final String svnUrl;

    @Autowired
    public UserService(@Value("${SVN_URL}") String svnUrl) {
        this.svnUrl = svnUrl;
    }
}

This approach is better for a few reasons:

由于以下几个原因,这种方法更好:

  • constructor injection describes directly what values are needed to initialize the object
  • finalfield means that this value wont be changed after it gets initialized in a constructor call (you are thread safe)
  • 构造函数注入直接描述了初始化对象需要什么值
  • final字段表示该值在构造函数调用中初始化后不会更改(您是线程安全的)

Using @ConfigurationProperties

使用 @ConfigurationProperties

There is also another way to load multiple properties to a single class. It requires using prefix for all values you want to load to your configuration class. Consider following example:

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

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

    private String svnUrl;

    private int somePort;

    // ... getters and setters
}

Spring will handle TestPropertiesclass initialization (it will create a testPropertiesbean) and you can inject this object to any other bean initialized by Spring container. And here is what exemplary application.propertiesfile look like:

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

test.svnUrl=https://svn.localhost.com/repo/
test.somePort=8080

Baeldung created a great post on this subject on his blog, I recommend reading it for more information.

Baeldung在他的博客上就这个主题发表了一篇很棒的文章,我建议阅读它以获取更多信息。

Alternative solution

替代方案

If you need somehow to use values in static context it's better to define some public class with public static finalfields inside - those values will be instantiated when classloader loads this class and they wont be modified during application lifetime. The only problem is that you won't be able to load these values from Spring's application.propertiesfile, you will have to maintain them directly in the code (or you could implement some class that loads values for these constants from properties file, but this sounds so verbose to the problem you are trying to solve).

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

回答by Patrick

Spring does not allow to inject value into static variables.

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

A workaround is to create a non static setter to assign your value into the static variable:

一种解决方法是创建一个非静态 setter 来将您的值分配给静态变量:

@Service
public class UserService {

    private static String SVN_URL;

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

}

回答by Jalaz Kumar

Accessing application.properties in static member functions is not allowed but here is a work around,

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

application.properties

应用程序属性

server.ip = 127.0.0.1

PropertiesExtractor.java

属性提取器.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);
        }
}

Main.class

主类

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")
    }
}