在項目中,一般會在類路徑下存在這樣的一個屬性文件,如:config.properties systemconfig.properties等,通過屬性文件可以實現以下目的 1. 統一維護公用的配置性屬性 2. 不修改class/jar,改變類的行為
一般還會針對此屬性文件提供一個類來讀取其屬性
本文介紹一種在設計公用代碼時的屬性文件通用設計思路,即多個屬性文件 1. 默認屬性文件 在公用代碼工程維護,發布時直接打包到jar中,其中的屬性會被2、3覆蓋 2. 各工程自定義屬性文件 在公用代碼工程不維護,使用者提供,其中屬性會被3覆蓋 3. 不可覆蓋的屬性文件 公用代碼工程維護,發布時直接打包到jar中
具體實現
1.Configuration 屬性讀取類
2.config.default.properties 默認屬性文件
3.config.properties 各工程自定義屬性文件
4.config.nooverride.properties 不可覆蓋的屬性文件
1.Configuration 屬性讀取類
package mov.demo;import java.io.IOException;import java.io.InputStream;import java.util.Properties;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * 屬性讀取類 * @author mov * @since 0.0.1 */public class Configuration { private static Logger log = LoggerFactory.getLogger(Configuration.class); private static Properties props = new Properties();; /** 默認屬性文件 */ private static final String CONFIG_FILE_DEFAULT = "config.default.properties"; /** 各工程自定義配置 */ private static final String CONFIG_FILE_USER_DEFINED = "config.properties"; /** 不可覆蓋的屬性文件 */ private static final String CONFIG_FILE_NO_OVERRIDE = "config.nooverride.properties"; static { int successLoadedCount = 0; /* 先加載默認配置 */ if (loadConfig(CONFIG_FILE_DEFAULT)) { ++successLoadedCount; } /* 再加載用戶自定義配置,以覆蓋默認 */ if (loadConfig(CONFIG_FILE_USER_DEFINED)) { ++successLoadedCount; } /* 最后加載不可覆蓋的配置,以覆蓋所有 */ if (loadConfig(CONFIG_FILE_NO_OVERRIDE)) { ++successLoadedCount; } if (successLoadedCount == 0) { log.error("all config file load error"); } } /** * 獲取屬性值 * @param key * @return 屬性存在時返回對應的值,否則返回"" */ public static String getCfgValue(String key) { return getCfgValue(key, ""); } /** * 獲取屬性值 * @param key * @param defaultValue * @return 屬性存在時返回對應的值,否則返回defaultValue */ public static String getCfgValue(String key, String defaultValue) { return props.getProperty(key, defaultValue); } /** * 獲取屬性值 * @param key * @return 屬性存在且可以轉為int時返回對應的值,否則返回0 */ public static int getIntCfgValue(String key) { return getIntCfgValue(key, 0); } /** * 獲取屬性值 * @param key * @param defaultValue * @return 屬性存在且可以轉為int時時返回對應的值,否則返回defaultValue */ public static int getIntCfgValue(String key, int defaultValue) { String val = getCfgValue(key); if (!isEmpty(val)) { try { return Integer.parseInt(val); } catch (NumberFormatException e) { log.warn("error get config. value '{}' is not a valid int for key '{}'" , val, key); } } return defaultValue; } /** * 獲取屬性值 * @param key * @return 屬性存在時返回對應的值,否則返回false */ public static boolean getBooleanCfgValue(String key) { return getBooleanCfgValue(key, false); } /** * 獲取屬性值 * @param key * @param defaultValue * @return 屬性存在時返回對應的值,否則返回defaultValue */ public static boolean getBooleanCfgValue(String key, boolean defaultValue) { String val = getCfgValue(key); if (!isEmpty(val)) { return Boolean.parseBoolean(val); } else { return defaultValue; } } private static boolean loadConfig(String configFile) { boolean success = false; InputStream inputStream = null; try { inputStream = Configuration.class.getClassLoader().getResourceAsStream(configFile); if (inputStream != null) { props.load(inputStream); success = true; } else { log.warn("project config file 'classpath:{}' not found", configFile); } } catch (Throwable e) { log.error("error load config file 'classpath:{}'", configFile, e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { // do nothing } } } return success; } private static boolean isEmpty(String val) { return val == null || val.length() == 0; }}
2.config.default.properties 默認屬性文件
string.in.default=defaultstring.in.defaultAndUserdefine=defaultstring.in.all=default
3.config.properties 各工程自定義屬性文件
string.in.defaultAndUserdefine=userdefinestring.in.all=userdefineint.positive=1000int.negative=-1000int.overflow=2147483648int.underflow=-2147483649boolean.true=TruEboolean.false=whatever4.config.nooverride.properties 不可覆蓋的屬性文件
string.in.all=nooverride
單元測試
package mov.demo;import static org.junit.Assert.*;import org.junit.Test;public class ConfigurationTest { @Test public void testGetCfgValueString() { assertEquals("", Configuration.getCfgValue("not.exists")); assertEquals("default", Configuration.getCfgValue("string.in.default")); assertEquals("userdefine", Configuration.getCfgValue("string.in.defaultAndUserdefine")); assertEquals("nooverride", Configuration.getCfgValue("string.in.all")); } @Test public void testGetCfgValueStringString() { assertEquals(null, Configuration.getCfgValue("not.exists", null)); assertEquals("default", Configuration.getCfgValue("string.in.default", null)); assertEquals("userdefine", Configuration.getCfgValue("string.in.defaultAndUserdefine", null)); assertEquals("nooverride", Configuration.getCfgValue("string.in.all", null)); } @Test public void testGetIntCfgValueString() { assertEquals(0, Configuration.getIntCfgValue("not.exists")); assertEquals(1000, Configuration.getIntCfgValue("int.positive")); assertEquals(-1000, Configuration.getIntCfgValue("int.negative")); assertEquals(0, Configuration.getIntCfgValue("int.overflow")); assertEquals(0, Configuration.getIntCfgValue("int.underflow")); } @Test public void testGetIntCfgValueStringInt() { assertEquals(-1, Configuration.getIntCfgValue("not.exists", -1)); assertEquals(1000, Configuration.getIntCfgValue("int.positive", -1)); assertEquals(-1000, Configuration.getIntCfgValue("int.negative", -1)); assertEquals(-1, Configuration.getIntCfgValue("int.overflow", -1)); assertEquals(-1, Configuration.getIntCfgValue("int.underflow", -1)); } @Test public void testGetBooleanCfgValueString() { assertFalse(Configuration.getBooleanCfgValue("not.exists")); assertTrue(Configuration.getBooleanCfgValue("boolean.true")); assertFalse(Configuration.getBooleanCfgValue("boolean.false")); } @Test public void testGetBooleanCfgValueStringBoolean() { assertTrue(Configuration.getBooleanCfgValue("not.exists", true)); assertTrue(Configuration.getBooleanCfgValue("boolean.true", false)); assertFalse(Configuration.getBooleanCfgValue("boolean.false", true)); }}
運行單元測試類,結果如下
源碼下載Github https://github.com/Mov-hh/java-demo
新聞熱點
疑難解答