>  기사  >  Java  >  속성 파일을 읽는 6가지 방법, 모아서 추천!

속성 파일을 읽는 6가지 방법, 모아서 추천!

Java后端技术全栈
Java后端技术全栈앞으로
2023-08-15 16:03:24470검색

손글씨 분산구성센터가 단계별로 진행중입니다.

요즘은 개발에 기본적으로 Spring Boot를 사용하는데 application.properties 구성 파일(일부는 application.yaml, 어쨌든 일부 구성 정보를 저장하는 데 사용됩니다. 일반적으로 다음과 같은 일부 구성 정보를 속성 파일에 기록합니다. 연결 정보, 타사 인터페이스 정보(키, 사용자 이름, 비밀번호, 주소 등), 연결 풀, Redis 구성 정보, 다양한 타사 구성 요소 구성 정보 등 application.properties配置文件(也有的是application.yaml,反正就是用来保存我们的一些配置信息),通常我们会把一些配置信息写到properties文件中,比如:数据库连接信息、第三方接口信息(密钥、用户名、密码、地址等),连接池、Redis配置信息、各种第三方组件配置信息等。

单体服务,甚至一些小型的分布式架构中,项目的配置都是依赖一个application.properties配置文件来解决(可能有的项目会搞一个环境区分,比如:application-dev.propertiesapplication-pro.properties

단일 서비스 및 일부 소규모 분산 아키텍처에서도 프로젝트 구성은 application.properties 구성 파일을 사용하여 문제를 해결합니다(일부 프로젝트에서는 다음과 같이 환경을 구분할 수 있습니다: application-dev.properties, application-pro.properties 등). 그러나 비즈니스가 발전하고 아키텍처가 계속 업그레이드됨에 따라 각 서비스에 관련된 서비스 데이터 및 구성 정보가 점점 더 많아지고 실시간 및 독립적 구성과 같은 구성 관리에 대한 요구 사항도 점점 더 높아질 것입니다. 정보. 섹스 등.

동시에 마이크로서비스 아키텍처에서는 구성 콘텐츠의 보안 및 권한을 포함하여 구성 관리, 그레이스케일 게시, 동적 전류 제한, 동적 다운그레이드 및 기타 환경 요구 사항이 포함될 수 있으므로 기존 구성 유지 관리 방법 수요를 충족시키기 어렵습니다.

그래서 분산 구성 센터는 그러한 환경에서 탄생했습니다.

이 기사에서는 먼저 Java에서 속성 구성 파일을 읽는 데 어떤 메서드가 있는지 알아봅니다. 🎜

Java가 속성 구성 파일을 읽는 6가지 방법

요구 사항 배경

요구 사항은 jdbc.properties 구성 파일은 다음과 같습니다. jdbc.properties 配置文件,内如如下:

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456

现在是想要在java代码中获取上面配置文件内容。

第一种方式

第一种方式我们采用:this.getClass().getResourceAsStream()+Properties

代码实现:

/**
* @author tianwc  公众号:java后端技术全栈、面试专栏
* @version 1.0.0
* @date 2023年05月27日 09:13
* 在线刷题1200+,100+篇干货文章:<a href="http://woaijava.cc/">博客地址</a>
*/
public void readProperties1() throws IOException {
    //不加/会从当前包进行寻找,加上/会从src开始找
    InputStream inputStream = this.getClass().getResourceAsStream("/jdbc.properties");
    Properties properties=new Properties();
    properties.load(inputStream);
    System.out.println("jdbc.driver="+properties.getProperty("jdbc.driver"));
    System.out.println("jdbc.url="+properties.getProperty("jdbc.url"));
    System.out.println("jdbc.username="+properties.getProperty("jdbc.username"));
    System.out.println("jdbc.password="+properties.getProperty("jdbc.password"));
}

下面来聊聊上面的这段代码:

this.getClass().getResourceAsStream()

具体文件和代码的位置是,代码在src/main/java目录下,资源文件在src/main/resources/

public synchronized void load(InputStream inStream) throws IOException {
        load0(new LineReader(inStream));
    }

    private void load0 (LineReader lr) throws IOException {
        char[] convtBuf = new char[1024];
        int limit;
        int keyLen;
        int valueStart;
        char c;
        boolean hasSep;
        boolean precedingBackslash;
        //逐行读取
        while ((limit = lr.readLine()) >= 0) {
            c = 0;
            keyLen = 0;
            valueStart = limit;
            hasSep = false;

            //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
            precedingBackslash = false;
            while (keyLen < limit) {
                c = lr.lineBuf[keyLen];
                //need check if escaped.
                if ((c == &#39;=&#39; ||  c == &#39;:&#39;) && !precedingBackslash) {
                    valueStart = keyLen + 1;
                    hasSep = true;
                    break;
                } else if ((c == &#39; &#39; || c == &#39;\t&#39; ||  c == &#39;\f&#39;) && !precedingBackslash) {
                    valueStart = keyLen + 1;
                    break;
                }
                if (c == &#39;\&#39;) {
                    precedingBackslash = !precedingBackslash;
                } else {
                    precedingBackslash = false;
                }
                keyLen++;
            }
            while (valueStart < limit) {
                c = lr.lineBuf[valueStart];
                if (c != &#39; &#39; && c != &#39;\t&#39; &&  c != &#39;\f&#39;) {
                    if (!hasSep && (c == &#39;=&#39; ||  c == &#39;:&#39;)) {
                        hasSep = true;
                    } else {
                        break;
                    }
                }
                valueStart++;
            }
            //前面一堆代码就是做校验和解析
            //下面两个是做转换
            String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
            String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
            
            put(key, value);
        }
    }

이제 Java 코드 내용에서 위 구성 파일을 가져오고 싶습니다. .

첫 번째 방법🎜🎜🎜🎜첫 번째 방법: this.getClass().getResourceAsStream()+속성🎜🎜코드 구현:🎜
public String getProperty(String key) {
    Object oval = super.get(key);
    String sval = (oval instanceof String) ? (String)oval : null;
    return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}
🎜위 코드에 대해 이야기해 보겠습니다.🎜

🎜🎜this.getClass().getResourceAsStream()🎜🎜

🎜특정 파일 및 코드 위치는, 코드는 src/main/java 디렉터리, 리소스 파일은 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px; background-color: rgba(27 , 31, 35, 0.05);글꼴군: " operator mono consolas monaco menlo monospace break-all rgb>src/main/ resources/ 디렉토리. 🎜🎜 현재 수업의 디렉터리에서 찾을 수 있습니다. 이 파일이 수업과 동일한 디렉터리에 없으면 찾을 수 없습니다. 🎜🎜전체 컴파일된 클래스 디렉터리에서 찾을 수 있습니다. Maven도 리소스 파일을 클래스 폴더에 패키징하여 찾을 수 있습니다. 🎜<p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;"><code style='font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);'>ClassLoader就是从整个classes文件夹找的,所以前面无需再加/

Properties

Properties:java.util.Properties,该类主要用于读取Java的配置文件,不同的编程语言有自己所支持的配置文件,配置文件中很多变量是经常改变的,为了方便用户的配置,能让用户够脱离程序本身去修改相关的变量设置。就像在Java中,其配置文件常为.properties文件,是以键值对的形式进行参数配置的。

类关系图:

속성 파일을 읽는 6가지 방법, 모아서 추천!

从上面的类图可以看到Properties类继承至Hashtable,相信大家都知道Hashtable是存储key-value数据结构类,也刚好对应我们properties文件内容也是key-value形式。

Properties 常见方法

getProperty(String key)   :在此属性列表中搜索具有指定键的属性。如果在此属性列表中找不到该键,则会检查默认属性列表及其默认值(递归)。如果未找到该属性,则该方法返回默认值参数。

list(PrintStream out) 이 속성 목록을 지정된 출력 스트림으로 인쇄합니다. 이 방법은 디버깅에 유용합니다.

load(InputStream inStream) : 입력에서 바이트 스트림에서 속성(키 및 요소 쌍) 목록을 읽습니다. 입력 스트림은 로더(Reader)에 지정된 간단한 라인 중심 형식이며 ISO 8859-1문자 인코딩, 즉 각 바이트는 Latin1 문자입니다. Latin1에 없는 문자와 특정 특수 문자는 유니코드 이스케이프를 사용하여 키와 요소에 표시됩니다. 이 메서드가 반환된 후에도 지정된 스트림은 열린 상태로 유지됩니다. load(InputStream inStream)  :从输入字节流中读取属性列表(键和元素对)。输入流采用加载(Reader)中指定的简单的面向行的格式,并假定使用ISO 8859-1字符编码;即每个字节是一个Latin1字符。不在Latin1中的字符和某些特殊字符在使用Unicode转义符的键和元素中表示。 此方法返回后,指定的流仍保持打开状态。

setProperty(String key, String  value) :调用 Hashtable 的方法 put 。他通过调用基类的put方法来设置 键值对。

store(OutputStream out, String comments) :将此Properties表中的此属性列表(键和元素对)以适合使用load(InputStream)方法加载到Properties表的格式写入输出流。 此Properties方法不会写出此Properties表的defaults表中的属性(如果有)。

storeToXML(OutputStream os, String comment, String encoding) :使用指定的编码发出表示此表中包含的所有属性的XML文档。

clear()  :清除此哈希表,使其不包含任何键。

stringPropertyNames()

setProperty(문자열 키, 문자열 값): Hashtable의 put 메소드를 호출합니다. 그는 기본 클래스의 put 메소드를 호출하여 키-값 쌍을 설정합니다. 🎜🎜store(OutputStream 출력, 문자열 주석) : load(InputStream) 메서드를 사용하여 Properties 테이블에 로드하는 데 적합한 형식으로 이 Properties 테이블의 속성(키 및 요소 쌍) 목록을 출력 스트림에 씁니다. 이 Properties 메서드는 이 Properties 테이블의 기본 테이블에 있는 속성(있는 경우)을 기록하지 않습니다. 🎜🎜storeToXML(OutputStream os, 문자열 주석, 문자열 인코딩) : 지정된 인코딩을 사용하여 이 테이블에 포함된 모든 속성을 나타내는 XML 문서를 내보냅니다. 🎜🎜clear() :이 해시 지우기 키가 포함되지 않도록 테이블을 만듭니다. 🎜🎜stringPropertyNames() : 이 속성을 반환합니다. 키와 해당 값이 문자열인 목록의 키 집합입니다. 기본 속성 목록에서 동일한 이름의 키를 찾을 수 없는 경우 기본 속성 목록의 다른 키를 포함합니다. 키가 문자열 유형이 아닌 키 또는 속성은 생략됩니다. 🎜
properties.load(inputStream)
public synchronized void load(InputStream inStream) throws IOException {
        load0(new LineReader(inStream));
    }

    private void load0 (LineReader lr) throws IOException {
        char[] convtBuf = new char[1024];
        int limit;
        int keyLen;
        int valueStart;
        char c;
        boolean hasSep;
        boolean precedingBackslash;
        //逐行读取
        while ((limit = lr.readLine()) >= 0) {
            c = 0;
            keyLen = 0;
            valueStart = limit;
            hasSep = false;

            //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
            precedingBackslash = false;
            while (keyLen < limit) {
                c = lr.lineBuf[keyLen];
                //need check if escaped.
                if ((c == &#39;=&#39; ||  c == &#39;:&#39;) && !precedingBackslash) {
                    valueStart = keyLen + 1;
                    hasSep = true;
                    break;
                } else if ((c == &#39; &#39; || c == &#39;\t&#39; ||  c == &#39;\f&#39;) && !precedingBackslash) {
                    valueStart = keyLen + 1;
                    break;
                }
                if (c == &#39;\\&#39;) {
                    precedingBackslash = !precedingBackslash;
                } else {
                    precedingBackslash = false;
                }
                keyLen++;
            }
            while (valueStart < limit) {
                c = lr.lineBuf[valueStart];
                if (c != &#39; &#39; && c != &#39;\t&#39; &&  c != &#39;\f&#39;) {
                    if (!hasSep && (c == &#39;=&#39; ||  c == &#39;:&#39;)) {
                        hasSep = true;
                    } else {
                        break;
                    }
                }
                valueStart++;
            }
            //前面一堆代码就是做校验和解析
            //下面两个是做转换
            String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
            String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
            
            put(key, value);
        }
    }

最后调用put(key, value);这个put方法就是Hashtable中的put方法。这里可以这么理解:将我们的配置项保存到Hashtable中。

getProperty(String key)
public String getProperty(String key) {
    Object oval = super.get(key);
    String sval = (oval instanceof String) ? (String)oval : null;
    return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}

super.get(key);就是调用Hashtable中的get()方法,也就是此时返回value,同时这就对应返回了properties文件中key对应的value。

第二种方式

第二种方式,我们通过当前类的加载器进行读取this.getClass().getClassLoader().getResourceAsStream()获取InputStream。

代码实现:

/**
* @author tianwc  公众号:java后端技术全栈、面试专栏
* @version 1.0.0
* @date 2023年05月27日 09:13
* 博客地址:<a href="http://woaijava.cc/">在线刷题1200+,100+篇干货文章</a>
*/
public void readProperties2() throws IOException {
    //不加/,若加了会为null
    InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("jdbc.properties");
    //如果放在config目录下
    //InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config/jdbc.properties");
    Properties properties=new Properties();
    properties.load(inputStream);
    System.out.println("jdbc.driver="+properties.getProperty("jdbc.driver"));
    System.out.println("jdbc.url="+properties.getProperty("jdbc.url"));
    System.out.println("jdbc.username="+properties.getProperty("jdbc.username"));
    System.out.println("jdbc.password="+properties.getProperty("jdbc.password"));
}

第一看怎么觉得和第一种方式很像,下面来说说两个的区别。

  • this.getClass.getResourceAsStream() 从当前类所에서 位置开始查找配置文件位置。要找到jdbc.properties必须加/从<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px; background-color: rgba(27, 31, 35, 0.05);글꼴 계열: " operator mono consolas monaco menlo monospace break-all rgb>classpath下开始查找
  • this.getClass.getResourceAsStream() 从当前类所在的位置开始查找配置文件位置。要找到jdbc.properties必须加/classpath下开始查找
  • this.getClass().getClassLoader().getResourceAsStream() 默认就从classpath路径下开始查找,加上/会报空指针异常
  • 剩下的部分代码和第一种方式一样,这里就不在赘述了。

    第三种方式

    接下来我们采用ClassLoader类的static方法 getSystemResourceAsStream()

    this.getClass( ).getClassLoader().getResourceAsStream() 默认就从클래스 경로路径下开始查找,加上/会报공공指针异常

    剩下적 부분은 代码와 第一种方式一样,赘述了。🎜

    第三种方式

    接下来我们采用ClassLoader 유형의 정적 방법 getSystemResourceAsStream()。🎜

    /**
    * @author tianwc  公众号:java后端技术全栈、面试专栏
    * @version 1.0.0
    * @date 2023年05月27日 09:13
    * 博客地址:<a href="http://woaijava.cc/">在线刷题1200+,100+篇干货文章</a>
    */
    public void readProperties3() throws IOException {
        //如果存放到config目录下
        //InputStream inputStream = ClassLoader.getSystemResourceAsStream("config/jdbc.properties");
        InputStream inputStream = ClassLoader.getSystemResourceAsStream("jdbc.properties");
        Properties properties=new Properties();
        properties.load(inputStream);
        System.out.println("jdbc.driver="+properties.getProperty("jdbc.driver"));
        System.out.println("jdbc.url="+properties.getProperty("jdbc.url"));
        System.out.println("jdbc.username="+properties.getProperty("jdbc.username"));
        System.out.println("jdbc.password="+properties.getProperty("jdbc.password"));
    }

    ClassLoader中的getSystemResourceAsStream()方法,它用于获取资源作为参数并将资源转换为InputStream。例如,我们可以使用该方法获取网站的静态资源并将其转换为InputStream

    说白了就是获取InputStream的方式不同罢了,最终还是交给Properties去解析jdbc.properties文件内容。

    第四种方式

    我们在实际开发中,基本上都是离不开Spring了,所以,接下来我们使用Spring中的 ClassPathResource读取配置文件。

    代码实现:

    /**
    * @author tianwc  公众号:java后端技术全栈、面试专栏
    * @version 1.0.0
    * @date 2023年05月27日 09:13
    * 博客地址:<a href="http://woaijava.cc/">博客地址</a>
    */
    public void readProperties4() throws IOException {
        ClassPathResource resource = new ClassPathResource("jdbc.properties");
        //ClassPathResource resource = new ClassPathResource("config/jdbc.properties");
        Properties properties= PropertiesLoaderUtils.loadProperties(resource);
        System.out.println("jdbc.driver="+properties.getProperty("jdbc.driver"));
        System.out.println("jdbc.url="+properties.getProperty("jdbc.url"));
        System.out.println("jdbc.username="+properties.getProperty("jdbc.username"));
        System.out.println("jdbc.password="+properties.getProperty("jdbc.password"));
    }

    这里PropertiesLoaderUtils是spring-core.jar下面的,全路径名称:

    org.springframework.core.io.support.PropertiesLoaderUtils

    PropertiesLoaderUtils.loadProperties(resource)源码部分:

    public static Properties loadProperties(EncodedResource resource) throws IOException {
        //创建一个Properties对象
        Properties props = new Properties();
        //处理文件内容并赋值给props
        fillProperties(props, resource);
        return props;
    }

    fillProperties(props, resource);方法:

    public static void fillProperties(Properties props, EncodedResource resource) throws IOException {
        fillProperties(props, resource, ResourcePropertiesPersister.INSTANCE);
    }
    
    static void fillProperties(Properties props, EncodedResource resource, PropertiesPersister persister) throws IOException {
        InputStream stream = null;
        Reader reader = null;
    
        try {
            //省略不相关代码
            stream = resource.getInputStream();
            //获取InputStream
            persister.load(props, stream); 
        } finally {
            //关闭
        }
    }

    最后到PropertiesPersisterpersister.load(props, stream);

    public void load(Properties props, InputStream is) throws IOException {
        props.load(is);
    }

    这里又回到Properties类中的load()方法里了。

    绕了半天也只是获取InputStream的方式不同而已

    第五种方式

    接下来我们来使用PropertyResourceBundle读取InputStream流,实现配置文件读取。

    代码实现:

    public void readProperties5() throws IOException {
        InputStream inputStream = ClassLoader.getSystemResourceAsStream("jdbc.properties");
        //InputStream inputStream = ClassLoader.getSystemResourceAsStream("config/jdbc.properties");
        PropertyResourceBundle bundle = new PropertyResourceBundle(inputStream);
        System.out.println(bundle.getString("jdbc.driver"));
        System.out.println(bundle.getString("jdbc.url"));
        System.out.println(bundle.getString("jdbc.username"));
        System.out.println(bundle.getString("jdbc.password"));
    }

    好像也没什么,

    PropertyResourceBundle源码

    我们来看看 new PropertyResourceBundle(inputStream);源码部分:

    public PropertyResourceBundle (InputStream stream) throws IOException {
        Properties properties = new Properties();
        properties.load(stream);
        lookup = new HashMap(properties);
    }

    这个构造方法里直接new了一个Properties对象。然后调用load方法解析。

    所以,这种方式无非就是在Properties基础之上再封装了,也就是让我们使用起来更加方便。

    PropertyResourceBundle类关系图

    속성 파일을 읽는 6가지 방법, 모아서 추천!

    所以,上面代码中的bundle.getString("jdbc.url")其实调用的是父类中方法;

    public final String getString(String key) {
        return (String) getObject(key);
    }

    最终调用到PropertyResourceBundlehandleGetObject()方法:

    public Object handleGetObject(String key) {
        if (key == null) {
            throw new NullPointerException();
        }
        return lookup.get(key);
    }

    lookup就是一个HashMap:lookup = new HashMap(properties);

    第六种方式

    第五种方式中我们看到了ResourceBundle,接下来我们就是用ResourceBundle.getBundle()实现。

    //不用输入后缀
    public void readProperties6()  {
        ResourceBundle bundle=ResourceBundle.getBundle("jdbc"); 
        System.out.println(bundle.getString("jdbc.driver"));
        System.out.println(bundle.getString("jdbc.url"));
        System.out.println(bundle.getString("jdbc.username"));
        System.out.println(bundle.getString("jdbc.password"));
    }

    直接使用文件名称就可以了,不需要写文件后缀名。

    java.util.ResourceBundle.getBundle(String baseName) 方法获取使用指定的基本名称,不需要文件后缀名,默认的语言环境和调用者的类加载器获取资源包。

    • baseName 이 null인 경우 예외 보고NullPointerException baseName 为 null ,则报异常NullPointerException
    • 如果可以找到指定的基没有相应的资源包 ,则报异常MissingResourceException
    if 지정된 베이스에 해당하는 리소스 패키지가 없으면 예외가 보고됩니다. MissingResourceException

    Summary

    위는 Java에서 일반적으로 속성 파일을 읽는 6가지 방법입니다.

    🎜🎜🎜

    위 내용은 속성 파일을 읽는 6가지 방법, 모아서 추천!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    이 기사는 Java后端技术全栈에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제