Java通过ResourceBundle获取properties配置
1、demo中考虑了配置读取并发问题(只是为了练练手而已,配置文件的一致性又不用考虑,手动狗头[旺财])
2、使用了单例模式,获取单例工具对象
3、增加了缓存机制,用以保存不同配置读取,节约资源,提高效率(貌似初始化的同步,效率更低)
4、既然是ResourceBundle,肯定只能读取properties文件啊!!
5、默认读取ISO-8859-1格式的配置文件,兼容Utf-8文件,但是需要手动指定ResourceBundler的isUtf8Code属性为true。
6、结合阿里的fastjson,进行ResourceBundle的包装,使用内部类ResourceBundler,并进行二次方法封装,使得能够获取更多样的配置对象(毕竟ResourceBundle的getStringArray看了源码都不知道怎么用,若有大佬了解,求告知啊)
import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.ResourceBundle; import com.alibaba.fastjson.JSONObject; import exclude.DataDef; /** * 工具类,获取src目录下的properties配置文件。 处理过单例工具类初始并发、以及读取配置并发 。确保并发读取配置不会出现覆盖读取 */ public class PropertiesLoader { private static volatile PropertiesLoader tools = null; private static volatile Map<String, ResourceBundler> bundlePool = null; /** * 单例模式的标准姿势 */ private PropertiesLoader() { } /** * 包装ResourceBundle对象,用于重新定义对象方法。可使得用户直接获取到可用bundle(方法已经可用) */ public class ResourceBundler { private ResourceBundle rb; private boolean isUtf8Code = false; private ResourceBundler() { } public boolean isUtf8Code() { return isUtf8Code; } public void setUtf8Code(boolean isUtf8Code) { this.isUtf8Code = isUtf8Code; } public ResourceBundler(ResourceBundle resourceBundle) { this(); rb = resourceBundle; } public String getString(String key) { return getPropertiesWithCode(key); } public List<String> getStringArray(String key) { String arrStr = getPropertiesWithCode(key); List<String> listValue = JSONObject.parseArray(arrStr, String.class); return listValue; } public List<Integer> getIntArray(String key) { String arrStr = getPropertiesWithCode(key); List<Integer> listValue = JSONObject.parseArray(arrStr, int.class); return listValue; } public <T> T getObject(String key, Class<T> type) { String json = getPropertiesWithCode(key); return JSONObject.parseObject(json, type); } public <T> List<T> getObjectArray(String key, Class<T> type) { String arrStr = getPropertiesWithCode(key); List<T> listValue = JSONObject.parseArray(arrStr, type); return listValue; } private String getPropertiesWithCode(String key) { String str = rb.getString(key); if (isUtf8Code) { try { return new String(str.getBytes("ISO-8859-1"), "UTF-8"); } catch (UnsupportedEncodingException e) { System.err.println("配置编码由ISO-8859-1转Utf-8发生异常"); e.printStackTrace(); } } return str; } } /** * 没有开放的构造的构造函数,肯定得给个函数处理工具类的获取。 * 控制并发问题,避免多线程任务获取到不同的工具类对象,导致后面读取不同配置时,后者覆盖前者。(先者读取好配置,后者才初始化) */ public synchronized static PropertiesLoader getPropertiesTools() { if (tools == null) { tools = new PropertiesLoader(); } return tools; }; /** * 获取指定配置文件中的一个字符串值 * * @param packageFileName "包名.文件名",不需要接后缀名,只读取properties文件 * @param key 需要获取的键名 * @return 键对应的值 */ public String getString(String packageFileName, String key) { return getPropertyValue(packageFileName, key, String.class); } /** * 获取指定配置文件中的一个字符串数组,字符间用逗号隔开 * * @param packageFileName "包名.文件名",不需要接后缀名,只读取properties文件 * @param key 需要获取的键名 * @return 键对应的值 */ public List<String> getStringArray(String packageFileName, String key) { return getPropertyArrayValue(packageFileName, key, String.class); } public List<Integer> getIntArray(String packageFileName, String key) { return getPropertyIntArrayValue(packageFileName, key); } public <T> T getObject(String packageFileName, String key, Class<T> type) { return getPropertyValue(packageFileName, key, type); } public <T> List<T> getObjectArray(String packageFileName, String key, Class<T> type) { return getPropertyArrayValue(packageFileName, key, type); } /** * 获取Bundle对象,解决某个对象需要暂存一个Bundle的需求 * * @param packageFileName "包名.文件名",不需要接后缀名,只读取properties文件 * @return ResourceBundle对象 */ public ResourceBundler getBundle(String packageFileName) { if (bundlePool == null) { initBundlePool(); } if (checkBundle(packageFileName)) { return bundlePool.get(packageFileName); } return createBundle(packageFileName); } /** * 获取指定配置文件中的,指定的一个值 * * @param packageFileName "包名.文件名",不需要接后缀名,只读取properties文件 * @param key 需要获取的键名 * @param T 需要获取的值类型 * @return 键对应的值 */ private <T> T getPropertyValue(String packageFileName, String key, Class<T> T) { if (bundlePool == null) { initBundlePool(); } ResourceBundler nameBundle = bundlePool.get(packageFileName); if (nameBundle != null) { return getValueByClazzType(nameBundle, key, T); } ResourceBundle rb = ResourceBundle.getBundle(packageFileName.trim()); ResourceBundler temp = new ResourceBundler(rb); bundlePool.put(packageFileName, temp); return getValueByClazzType(temp, key, T); } /** * 获取指定配置文件中的,指定类型的一个数组 * * @param packageFileName "包名.文件名",不需要接后缀名,只读取properties文件 * @param key 需要获取的键名 * @param T 需要获取的值类型 * @return 键对应的值 */ private <T> List<T> getPropertyArrayValue(String packageFileName, String key, Class<T> T) { if (bundlePool == null) { initBundlePool(); } ResourceBundler nameBundle = bundlePool.get(packageFileName); if (nameBundle != null) { return getArrayByClazzType(nameBundle, key, T); } ResourceBundle rb = ResourceBundle.getBundle(packageFileName.trim()); ResourceBundler temp = new ResourceBundler(rb); bundlePool.put(packageFileName, temp); return getArrayByClazzType(temp, key, T); } /** * 针对不同的配置对象需求获取不同类型的值(集合) * * @param bundle 值所存在的Bundle对象 * @param key 被查询值的键名 * @param type 预期值的类型 * @return 被查询的值(集合) */ @SuppressWarnings("unchecked") private <T> List<T> getArrayByClazzType(ResourceBundler bundler, String key, Class<T> type) { if (type == String.class) { return (List<T>) bundler.getStringArray(key); } else if (type == Integer.class) { return (List<T>) bundler.getIntArray(key); } else { return (List<T>) bundler.getObjectArray(key, type); } } /** * 获取指定配置文件中的,int值的数组 * * @param packageFileName "包名.文件名",不需要接后缀名,只读取properties文件 * @param key 需要获取的键名 * @param T 需要获取的值类型 * @return 键对应的值 */ private List<Integer> getPropertyIntArrayValue(String packageFileName, String key) { if (bundlePool == null) { initBundlePool(); } ResourceBundler nameBundle = bundlePool.get(packageFileName); if (nameBundle != null) { return getIntArrayByClazzType(nameBundle, key); } ResourceBundle rb = ResourceBundle.getBundle(packageFileName.trim()); ResourceBundler temp = new ResourceBundler(rb); bundlePool.put(packageFileName, temp); return getIntArrayByClazzType(temp, key); } /** * 根据文件名创建相应的Bundle,并缓存做缓存。创建时同步是为了预防一个配置都被读取两次(看并发情况,其实可以不使用同步) * * @param packageFileName "包名.文件名",不需要接后缀名,只读取properties文件 */ private synchronized ResourceBundler createBundle(String packageFileName) { if (checkBundle(packageFileName)) { return bundlePool.get(packageFileName); } ResourceBundle rb = ResourceBundle.getBundle(packageFileName.trim()); ResourceBundler temp = new ResourceBundler(rb); bundlePool.put(packageFileName, temp); return temp; } /** * 检查缓存中是否有存在读取过的配置 * * @param packageFileName "包名.文件名",不需要接后缀名,只读取properties文件 * @return 存在缓存的逻辑值 */ private boolean checkBundle(String packageFileName) { ResourceBundler nameBundler = bundlePool.get(packageFileName); if (nameBundler != null) { return true; } return false; } /** * 针对不同的配置对象需求获取不同类型的值 * * @param bundle 值所存在的Bundle对象 * @param key 被查询值的键名 * @param type 预期值的类型 * @return 被查询的值 */ @SuppressWarnings("unchecked") private <T> T getValueByClazzType(ResourceBundler bundler, String key, Class<T> type) { if (type == String.class) { return (T) bundler.getString(key); } else { return (T) bundler.getObject(key, type); } } /** * 针对不同的配置对象需求获取int类型的值(集合) * * @param bundle 值所存在的Bundle对象 * @param key 被查询值的键名 * @param type 预期值的类型 * @return 被查询的值(集合) */ private List<Integer> getIntArrayByClazzType(ResourceBundler bundler, String key) { return bundler.getIntArray(key); } /** * 初始化缓存容器,同步避免缓存被覆盖 */ private synchronized void initBundlePool() { if (bundlePool == null) { bundlePool = new HashMap<String, ResourceBundler>(); } } }
测试用的模板类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import java.util.Date; import java.util.List; public class DataDef { public String name; public int age; public List<String> strArray; public List<DataDef> objArray; public Date dateTime; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public List<String> getStrArray() { return strArray; } public void setStrArray(List<String> strArray) { this.strArray = strArray; } public Date getDateTime() { return dateTime; } public List<DataDef> getObjArray() { return objArray; } public void setObjArray(List<DataDef> objArray) { this.objArray = objArray; } public void setDateTime(Date dateTime) { this.dateTime = dateTime; } @Override public String toString() { return "DataDef [name=" + name + ", strArray=" + strArray + ", objArray=" + objArray + ", dateTime=" + dateTime + "]"; } }
测试主方法
public static void main(String[] args) { PropertiesLoader tools = PropertiesLoader.getPropertiesTools(); ResourceBundler bundler = tools.getBundle("exclude.test"); ResourceBundler bundler2 = tools.getBundle("exclude.test2"); DataDef data = bundler.getObject("s", DataDef.class); System.out.println("data对象" + data.toString()); System.out.println(); String jsonNumArrayString = tools.getString("exclude.test", "nums"); System.out.println(jsonNumArrayString); List<Integer> numArr = bundler.getIntArray("nums"); System.out.println("数字数组:" + numArr); Integer[] arrs = numArr.toArray(new Integer[6]); for (Integer num : arrs) { System.out.println(num); } System.out.println(); String jsonStrArrayString = bundler.getString("NecessaryNameHead"); System.out.println(jsonStrArrayString); bundler2.setUtf8Code(true); List<String> jsonStrArrayString2 = bundler2.getStringArray("NecessaryNameHead"); System.out.println(jsonStrArrayString2); List<String> strArr = bundler.getStringArray("strs"); System.out.println("String数组:" + strArr); for (String string : strArr) { System.out.println(string); } }
随笔为本人学习笔记以及个人看法,若有错误,欢迎指正