Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中,从配置文件读取配置参数的最佳方法是什么?_Java_Oop_Configuration_Initialization_Runtime - Fatal编程技术网

在Java中,从配置文件读取配置参数的最佳方法是什么?

在Java中,从配置文件读取配置参数的最佳方法是什么?,java,oop,configuration,initialization,runtime,Java,Oop,Configuration,Initialization,Runtime,假设到运行时为止,我们不知道配置的详细信息(在运行应用程序之前,用户可能需要在config文件中配置这些参数) 我想阅读这些配置详细信息,并需要在我的应用程序中需要它们的地方重用它们。为此,我想将它们作为全局常量(publicstaticfinal) 因此,我的疑问是,如果我直接从所需类读取config文件,是否会对性能产生影响?因为,运行时值不能直接放在单独的接口中 我认为这会影响性能。请给我建议更好的方法 更新:我可以使用单独的最终类获取配置详细信息吗? 将所有配置详细信息作为常量放在单独的

假设到运行时为止,我们不知道配置的详细信息(在运行应用程序之前,用户可能需要在
config
文件中配置这些参数)

我想阅读这些配置详细信息,并需要在我的应用程序中需要它们的地方重用它们。为此,我想将它们作为全局常量(
publicstaticfinal

因此,我的疑问是,如果我直接从所需类读取
config
文件,是否会对性能产生影响?因为,运行时值不能直接放在单独的
接口中

我认为这会影响性能。请给我建议更好的方法

更新:我可以使用单独的最终类获取配置详细信息吗? 将所有配置详细信息作为常量放在单独的
公共最终类中


(一次从配置文件中读取所有配置详细信息,并将其存储为全局常量,以供以后在应用程序中使用)

如果将其放入属性文件中,并在应用程序开始时读取该文件,并将所有参数初始化为系统参数,则只需一次成本(System.setProperty)然后在代码中定义常量,如

public static final String MY_CONST = System.getProperty("my.const");
但在加载任何其他类之前,请确保在应用程序启动时进行初始化

我认为这会影响性能

我怀疑这是真的

假设应用程序在启动时只读取一次配置文件,则读取文件所需的时间可能与应用程序的总体性能无关。实际上,应用程序运行的时间越长,启动时间就越不重要

标准建议是,只有当您有具体证据(即度量)表明性能是一个重要问题时,才对应用程序性能进行优化。然后,只优化那些分析表明您确实是性能瓶颈的代码部分


我可以使用单独的最终类获取配置详细信息吗

是的,这是可能的。没有人会阻止你。 然而,这是一个坏主意。任何意味着您需要重新编译代码来更改配置参数的事情都是一个坏主意


一次从配置文件中读取所有配置详细信息,并将其存储为全局常量,以便以后在应用程序中使用

啊…所以你实际上想读取“常数”的值,而不是硬连接它们

是的,这是可能的。这比将配置参数硬连接到代码中更有意义。但这仍然不是一个好主意(IMO)

为什么?让我们看看代码应该是什么样子:

public final class Config { 
    public static final int CONST_1;
    public static final String CONST_2;
   
    static {
        int c1;
        String c2;
        try (Scanner s = new Scanner(new File("config.txt"))) {
            c1 = s.nextInt();
            c2 = s.next();
        } catch (IOException ex) {
            throw RuntimeException("Cannot load config properties", ex);
        }
        CONST_1 = c1;
        CONST_2 = c2; 
    }
}
第一个观察结果是,类是
final
没有区别。将字段声明为
final
使其保持不变(将类声明为
final
可以防止子类化,但这对
静态
字段没有影响。静态字段不受继承的影响。)

下一个观察结果是,该代码在许多方面都是脆弱的:

  • 如果静态初始值设定项块出错。该块引发的未检查异常将被包装为
    异常InInitializeError
    (是…这是
    错误
    !!),并且
    配置
    类将被标记为错误

  • 如果发生这种情况,就没有实际的恢复希望,尝试诊断
    错误甚至可能是个坏主意

  • 上面的代码在
    Config
    类初始化时执行,但确定何时执行可能很棘手

  • 如果配置文件名是一个参数,那么在触发静态初始化之前,您会遇到获取参数值的问题

其次,与将状态加载到实例变量相比,代码非常混乱。这种混乱很大程度上是由于必须在静态初始值设定项的约束范围内工作。以下是使用
final
实例变量时代码的外观

public final class Config { 
    public final int CONST_1;
    public final String CONST_2;
   
    public Config(File file) throws IOException {
        try (Scanner s = new Scanner(file)) {
            CONST_1 = s.nextInt();
            CONST_2 = s.next();
        } 
    }
}
最后,
static final
字段相对于
final
字段的性能优势很小:

  • 每次访问一个常量时,可能会有一个或两个机器指令

  • 如果JIT编译器是智能的,并且您可以适当地处理singleton
    Config
    引用,那么可能什么都没有

无论哪种情况,在绝大多数情况下,好处都是微不足道的



1-好的…如果您的代码经过代码审查,那么可能会有人阻止您。

将配置键直接放在类中是不好的:配置键将分散在代码中。最佳做法是将应用程序代码和配置代码分离。通常使用spring之类的依赖项注入框架。它加载配置,并使用配置值构造对象。如果类中需要某些配置值,则应为此值创建一个setter。Spring将在上下文初始化期间设置此值。

另一种方法是定义类并读取该类中的属性文件。 此类需要位于应用程序级别,并且可以标记为Singleton。
将类标记为Singleton将避免创建多个实例。

您听说过apache commons配置吗? 这是我所发现的最好的配置阅读器,甚至我正在我的应用程序中使用它,该应用程序自1年以来一直在生产中运行。从未发现任何问题,非常易于理解和使用,性能优异。我知道它对您的应用程序有点依赖,但相信我,您会喜欢它的

Configuration config = new ConfigSelector().getPropertiesConfiguration(configFilePath);
String value = config.getString("key");
int value1 = config.getInt("key1");
String[] value2 = config.getStringArray("key2");
List<Object> value3 = config.getList("key3");
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ApplicationConfig {

    private static final JAXBContext CONTEXT;
    public static final ApplicationConfig INSTANCE;

    // configuration properties with defaults
    private int number = 0;
    private String text = "default";
    @XmlElementWrapper
    @XmlElement(name = "text")
    private List<String> texts = new ArrayList<>(Arrays.asList("default1", "default2"));

    ApplicationConfig() {
    }

    static {
        try {
            CONTEXT = JAXBContext.newInstance(ApplicationConfig.class);
        } catch (JAXBException ex) {
            throw new IllegalStateException("JAXB context for " + ApplicationConfig.class + " unavailable.", ex);
        }
        File applicationConfigFile = new File(System.getProperty("config", new File(System.getProperty("user.dir"), "config.xml").toString()));
        if (applicationConfigFile.exists()) {
            INSTANCE = loadConfig(applicationConfigFile);
        } else {
            INSTANCE = new ApplicationConfig();
        }
    }

    public int getNumber() {
        return number;
    }

    public String getText() {
        return text;
    }

    public List<String> getTexts() {
        return Collections.unmodifiableList(texts);
    }

    public static ApplicationConfig loadConfig(File file) {
        try {
            return (ApplicationConfig) CONTEXT.createUnmarshaller().unmarshal(file);
        } catch (JAXBException ex) {
            throw new IllegalArgumentException("Could not load configuration from " + file + ".", ex);
        }
    }

    // usage
    public static void main(String[] args) {
        System.out.println(ApplicationConfig.INSTANCE.getNumber());
        System.out.println(ApplicationConfig.INSTANCE.getText());
        System.out.println(ApplicationConfig.INSTANCE.getTexts());
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<applicationConfig>
    <number>12</number>
    <text>Test</text>
    <texts>
        <text>Test 1</text>
        <text>Test 2</text>
    </texts>
</applicationConfig>
public class Configuration {

    // the configuration file is stored in the root of the class path as a .properties file
    private static final String CONFIGURATION_FILE = "/configuration.properties";

    private static final Properties properties;

    // use static initializer to read the configuration file when the class is loaded
    static {
        properties = new Properties();
        try (InputStream inputStream = Configuration.class.getResourceAsStream(CONFIGURATION_FILE)) {
            properties.load(inputStream);
        } catch (IOException e) {
            throw new RuntimeException("Failed to read file " + CONFIGURATION_FILE, e);
        }
    }

    public static Map<String, String> getConfiguration() {
        // ugly workaround to get String as generics
        Map temp = properties;
        Map<String, String> map = new HashMap<String, String>(temp);
        // prevent the returned configuration from being modified 
        return Collections.unmodifiableMap(map);
    }


    public static String getConfigurationValue(String key) {
        return properties.getProperty(key);
    }

    // private constructor to prevent initialization
    private Configuration() {
    }

}
  protected java.util.Properties loadParams() throws IOException {
  // Loads a ResourceBundle and creates Properties from it
  Properties prop = new Properties();
  URL propertiesFileURL = this.getClass().getResource("/conf/config.properties");
  prop.load(new FileInputStream(new File(propertiesFileURL.getPath())));
  return prop;
  }


Properties prop = loadParams();
String prop1=(String) prop.get("x.y.z");