손글씨 분산구성센터가 단계별로 진행중입니다.
요즘은 개발에 기본적으로 Spring Boot를 사용하는데 application.properties
구성 파일(일부는 application.yaml
, 어쨌든 일부 구성 정보를 저장하는 데 사용됩니다. 일반적으로 다음과 같은 일부 구성 정보를 속성 파일에 기록합니다. 연결 정보, 타사 인터페이스 정보(키, 사용자 이름, 비밀번호, 주소 등), 연결 풀, Redis 구성 정보, 다양한 타사 구성 요소 구성 정보 등 application.properties
配置文件(也有的是application.yaml
,反正就是用来保存我们的一些配置信息),通常我们会把一些配置信息写到properties文件中,比如:数据库连接信息、第三方接口信息(密钥、用户名、密码、地址等),连接池、Redis配置信息、各种第三方组件配置信息等。
单体服务,甚至一些小型的分布式架构中,项目的配置都是依赖一个application.properties
配置文件来解决(可能有的项目会搞一个环境区分,比如:application-dev.properties
、application-pro.properties
application.properties
구성 파일을 사용하여 문제를 해결합니다(일부 프로젝트에서는 다음과 같이 환경을 구분할 수 있습니다: application-dev.properties
, application-pro.properties
등). 그러나 비즈니스가 발전하고 아키텍처가 계속 업그레이드됨에 따라 각 서비스에 관련된 서비스 데이터 및 구성 정보가 점점 더 많아지고 실시간 및 독립적 구성과 같은 구성 관리에 대한 요구 사항도 점점 더 높아질 것입니다. 정보. 섹스 등. 동시에 마이크로서비스 아키텍처에서는 구성 콘텐츠의 보안 및 권한을 포함하여 구성 관리, 그레이스케일 게시, 동적 전류 제한, 동적 다운그레이드 및 기타 환경 요구 사항이 포함될 수 있으므로 기존 구성 유지 관리 방법 수요를 충족시키기 어렵습니다. 그래서 분산 구성 센터는 그러한 환경에서 탄생했습니다. 이 기사에서는 먼저 Java에서 속성 구성 파일을 읽는 데 어떤 메서드가 있는지 알아봅니다. 🎜요구 사항은 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/
이제 Java 코드 내용에서 위 구성 파일을 가져오고 싶습니다. . 첫 번째 방법🎜🎜🎜🎜첫 번째 방법: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 == '=' || c == ':') && !precedingBackslash) { valueStart = keyLen + 1; hasSep = true; break; } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) { valueStart = keyLen + 1; break; } if (c == '\') { precedingBackslash = !precedingBackslash; } else { precedingBackslash = false; } keyLen++; } while (valueStart < limit) { c = lr.lineBuf[valueStart]; if (c != ' ' && c != '\t' && c != '\f') { if (!hasSep && (c == '=' || c == ':')) { 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); } }로그인 후 복사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> 디렉터리, 리소스 파일은 <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;color: rgb(239, 112, 96);">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
文件,是以键值对的形式进行参数配置的。类关系图:
从上面的类图可以看到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()
:清除此哈希表,使其不包含任何键。<코드 스타일="글꼴 크기: 14px;패딩: 2px 4px;국경 반경: 4px;마진-오른쪽: 2px;마진-왼쪽: 2px;배경-색상: rgba(27, 31, 35, 0.05) ;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">setProperty(문자열 키, 문자열 값): Hashtable의 put 메소드를 호출합니다. 그는 기본 클래스의 put 메소드를 호출하여 키-값 쌍을 설정합니다. 🎜🎜<코드 스타일="글꼴 크기: 14px;패딩: 2px 4px;국경 반경: 4px;마진-오른쪽: 2px;마진-왼쪽: 2px;배경-색상: rgba(27, 31, 35, 0.05) ;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">store(OutputStream 출력, 문자열 주석) : load(InputStream) 메서드를 사용하여 Properties 테이블에 로드하는 데 적합한 형식으로 이 Properties 테이블의 속성(키 및 요소 쌍) 목록을 출력 스트림에 씁니다. 이 Properties 메서드는 이 Properties 테이블의 기본 테이블에 있는 속성(있는 경우)을 기록하지 않습니다. 🎜🎜<코드 스타일="글꼴 크기: 14px;패딩: 2px 4px;국경 반경: 4px;마진-오른쪽: 2px;마진-왼쪽: 2px;배경-색상: rgba(27, 31, 35, 0.05) ;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">storeToXML(OutputStream os, 문자열 주석, 문자열 인코딩) : 지정된 인코딩을 사용하여 이 테이블에 포함된 모든 속성을 나타내는 XML 문서를 내보냅니다. 🎜🎜<코드 스타일="글꼴 크기: 14px;패딩: 2px 4px;국경 반경: 4px;마진-오른쪽: 2px;마진-왼쪽: 2px;배경-색상: rgba(27, 31, 35, 0.05) ;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">clear() :이 해시 지우기 키가 포함되지 않도록 테이블을 만듭니다. 🎜🎜<코드 스타일="글꼴 크기: 14px;패딩: 2px 4px;국경 반경: 4px;마진-오른쪽: 2px;마진-왼쪽: 2px;배경-색상: rgba(27, 31, 35, 0.05) ;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">stringPropertyNames() : 이 속성을 반환합니다. 키와 해당 값이 문자열인 목록의 키 집합입니다. 기본 속성 목록에서 동일한 이름의 키를 찾을 수 없는 경우 기본 속성 목록의 다른 키를 포함합니다. 키가 문자열 유형이 아닌 키 또는 속성은 생략됩니다. 🎜
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 == '=' || c == ':') && !precedingBackslash) { valueStart = keyLen + 1; hasSep = true; break; } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) { valueStart = keyLen + 1; break; } if (c == '\\') { precedingBackslash = !precedingBackslash; } else { precedingBackslash = false; } keyLen++; } while (valueStart < limit) { c = lr.lineBuf[valueStart]; if (c != ' ' && c != '\t' && c != '\f') { if (!hasSep && (c == '=' || c == ':')) { 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")); }로그인 후 복사第一看怎么觉得和第一种方式很像,下面来说说两个的区别。
<코드 스타일="글꼴 크기: 14px;패딩: 2px 4px;국경 반경: 4px;마진 오른쪽: 2px;마진 왼쪽: 2px;배경 색상: rgba(27, 31, 35, 0.05 );font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">this.getClass.getResourceAsStream() 从当前类所에서 位置开始查找配置文件位置。要找到 jdbc.properties
必须加/< /code>从<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;word-break: break-all;color: rgb(239, 112, 96);">classpath
下开始查找< /section>this.getClass.getResourceAsStream()
从当前类所在的位置开始查找配置文件位置。要找到jdbc.properties
必须加/
从classpath
下开始查找
this.getClass().getClassLoader().getResourceAsStream()
默认就从classpath
路径下开始查找,加上/
会报空指针异常。剩下的部分代码和第一种方式一样,这里就不在赘述了。
接下来我们采用ClassLoader
类的static方法 getSystemResourceAsStream()
this.getClass( ).getClassLoader().getResourceAsStream()
默认就从클래스 경로
路径下开始查找,加上/
会报공공指针异常。< h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight:bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;">第三种方式剩下적 부분은 代码와 第一种方式一样,赘述了。🎜
接下来我们采用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 { //关闭 } }
最后到PropertiesPersister
的persister.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基础之上再封装了,也就是让我们使用起来更加方便。
所以,上面代码中的bundle.getString("jdbc.url")
其实调用的是父类中方法;
public final String getString(String key) { return (String) getObject(key); }
最终调用到PropertyResourceBundle
的handleGetObject()
方法:
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)
方法获取使用指定的基本名称,不需要文件后缀名,默认的语言环境和调用者的类加载器获取资源包。if 지정된 베이스에 해당하는 리소스 패키지가 없으면 예외가 보고됩니다.
baseName
이 null인 경우 예외 보고NullPointerException
baseName
为 null ,则报异常NullPointerException
如果可以找到指定的基没有相应的资源包 ,则报异常 MissingResourceException
MissingResourceException
위 내용은 속성 파일을 읽는 6가지 방법, 모아서 추천!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!