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>();
        }
    }
}

 

 

测试用的模板类

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

 

posted @ 2021-12-14 19:22  我吃柠檬  阅读(336)  评论(0编辑  收藏  举报