我有一些代码使用了一个包含大量硬编码常量的类。这就是它的样子:
class Constants{
public static final String name1 = "value1";
public static final String name2 = "value2";
public static final Integer value3 = 3;
... and so on
}
这些常量在代码中的任何地方都使用,如Constants.name1
。
我现在需要做的是在配置文件中指定这些常量的值,可能是*.properties
文件。
我的问题是:最好的方法是什么,必须尽可能少地重写代码?
我想过使用一个配置类,它在实例化时从文件中读取属性,但是我必须将值的所有静态调用替换为对该类实例的调用,我将不得不改变现有方法将此配置实例传递给它们。还有更好的方法吗?
答案 0 :(得分:4)
以下是我过去使用的一段代码 - 可以根据您的示例进行调整:
public enum Configuration {
PROPERTY1("property1.name", "default_value_1"),
PROPERTY2("property2.name", "default_value_2");
private final String key;
private String defaultValue;
Configuration(String key) {
this(key, NA);
}
Configuration(String key, String defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
}
private final static Logger logger = LoggerFactory.getLogger(Configuration.class);
private final static String NA = "n.a.";
private final static String CONFIG_FILE = "properties/config.properties";
private final static String NOT_A_VALID_KEY = "Not a valid property key";
private final static Map<Configuration, String> configuration = new EnumMap<>(Configuration.class);
static {
readConfigurationFrom(CONFIG_FILE);
}
private static void readConfigurationFrom(String fileName) {
logger.info("Reading resource: {}", fileName);
try (InputStream resource = Configuration.class.getClassLoader().getResourceAsStream(fileName);) {
Properties properties = new Properties();
properties.load(resource); //throws a NPE if resource not founds
for (String key : properties.stringPropertyNames()) {
configuration.put(getConfigurationKey(key), properties.getProperty(key));
}
} catch (IllegalArgumentException | IOException | NullPointerException e) {
logger.error("Error while reading the properties file {}", fileName, e);
populateDefaultValues();
}
}
private static Configuration getConfigurationKey(String key) {
for (Configuration c : values()) {
if (c.key.equals(key)) {
return c;
}
}
throw new IllegalArgumentException(NOT_A_VALID_KEY + ": " + key);
}
private static void populateDefaultValues() {
for (Configuration c : values()) {
configuration.put(c, c.defaultValue);
}
}
/**
* @return the property corresponding to the key or null if not found
*/
public String get() {
return configuration.get(this);
}
}
答案 1 :(得分:3)
使用Properties.load(...)
从文件加载属性,并从这些属性中分配常量。
class Constants{
public static final String name1;
public static final String name2;
public static final Integer value3;
static{
Properties p = new Properties();
try ( FileInputStream stream = new FileInputStream( new File("path/to/file.properties") )) {
p.load( stream );
}catch( Exception e ){
//handle exceptions
}
name1 = p.getProperty( "name1" );
name2 = p.getProperty( "name2" );
value3 = Integer.valueOf( p.getProperty( "value3" ) );
}
请注意,这只是一个快速而肮脏的解决方案,并做了很多假设。处理单个异常会更好,如果配置为空或不是数字,您还必须处理NumberFormatException
可能抛出的Integer.valueOf(...)
。
另一个注意事项:您也可以尝试使用一些非静态或至少非最终配置,以便能够在运行时更改属性。
编辑:我为该流添加了autoclose,但请注意,在Java 7之前,您必须自己处理。
答案 2 :(得分:2)
作为一个快速入侵,您可以在类的static
初始值设定项中读取属性文件,然后您不必立即更改类字段的静态性质,但我建议您仍然这样做随着时间的推移。
创建一个包含所有旧常量值的新类。从现在开始,将此配置对象注入新代码中。
class NewConstants {
public final String name1;
public final String name2;
public final Integer value3;
... and so on
public NewConstants ( Properties props )
{
name1 = props.getProperty( "name1" );
...
}
}
现在重构您的旧Constants
类
class Constants (
public static final String name1;
public static final String name2;
public static final Integer value3;
static {
Properties props = new Poperties( );
props.load( ... );
NewConstants newConstants = new NewConstants( props );
name1 = newConstants.getName1( );
name2 = newConstants.getName2( );
...
}
}