image frame

无论走到哪里,
都应该记住,
过去都是假的,
回忆是一条没有尽头的路。
一切以往的春天都不复存在,
就连那最坚韧而又狂乱的爱情,
归根结底也不过是转瞬即逝的现实,
唯有孤独永恒。

——加西亚·马尔克斯

Properties 源码

概括

Properties 继承 Hashtable ,是线程安全的,主要用于读取配置文件。

继承结构

Properties继承结构

  • 继承 Hashtable,是线程安全的;
  • 实现 Map 接口,有 Map 的属性;

构造方法

View Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* A property list that contains default values for any keys not
* found in this property list.
*
* @serial
*/
protected Properties defaults;

/**
* Creates an empty property list with no default values.
*/
public Properties() {
this(null);
}

/**
* Creates an empty property list with the specified defaults.
*
* @param defaults the defaults.
*/
public Properties(Properties defaults) {
this.defaults = defaults;
}
  • 初始化 Properties 设定默认值;

操作方法

View Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/**
*
* <p>
* A natural line that contains only white space characters is
* considered blank and is ignored. A comment line has an ASCII
* {@code '#'} or {@code '!'} as its first non-white
* space character; comment lines are also ignored and do not
* encode key-element information. In addition to line
* terminators, this format considers the characters space
* ({@code ' '}, {@code '\u005Cu0020'}), tab
* ({@code '\t'}, {@code '\u005Cu0009'}), and form feed
* ({@code '\f'}, {@code '\u005Cu000C'}) to be white
* space.
*
* <p>
* The key contains all of the characters in the line starting
* with the first non-white space character and up to, but not
* including, the first unescaped {@code '='},
* {@code ':'}, or white space character other than a line
* terminator. All of these key termination characters may be
* included in the key by escaping them with a preceding backslash
* character; for example,<p>
*
* {@code \:\=}<p>
*
* would be the two-character key {@code ":="}. Line
* terminator characters can be included using {@code \r} and
* {@code \n} escape sequences. Any white space after the
* key is skipped; if the first non-white space character after
* the key is {@code '='} or {@code ':'}, then it is
* ignored and any white space characters after it are also
* skipped. All remaining characters on the line become part of
* the associated element string; if there are no remaining
* characters, the element is the empty string
* {@code ""}. Once the raw character sequences
* constituting the key and element are identified, escape
* processing is performed as described above.
*
* <p>
* As an example, each of the following three lines specifies the key
* {@code "Truth"} and the associated element value
* {@code "Beauty"}:
* <pre>
* Truth = Beauty
* Truth:Beauty
* Truth :Beauty
* </pre>
* As another example, the following three lines specify a single
* property:
* <pre>
* fruits apple, banana, pear, \
* cantaloupe, watermelon, \
* kiwi, mango
* </pre>
* The key is {@code "fruits"} and the associated element is:
* <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
* Note that a space appears before each {@code \} so that a space
* will appear after each comma in the final result; the {@code \},
* line terminator, and leading white space on the continuation line are
* merely discarded and are <i>not</i> replaced by one or more other
* characters.
* <p>
* As a third example, the line:
* <pre>cheeses
* </pre>
* specifies that the key is {@code "cheeses"} and the associated
* element is the empty string {@code ""}.
* <p>
* <a name="unicodeescapes"></a>
* Characters in keys and elements can be represented in escape
* sequences similar to those used for character and string literals
* (see sections 3.3 and 3.10.6 of
* <cite>The Java&trade; Language Specification</cite>).
*
* The differences from the character escape sequences and Unicode
* escapes used for characters and strings are:
*
* <ul>
* <li> Octal escapes are not recognized.
*
* <li> The character sequence {@code \b} does <i>not</i>
* represent a backspace character.
*
* <li> The method does not treat a backslash character,
* {@code \}, before a non-valid escape character as an
* error; the backslash is silently dropped. For example, in a
* Java string the sequence {@code "\z"} would cause a
* compile time error. In contrast, this method silently drops
* the backslash. Therefore, this method treats the two character
* sequence {@code "\b"} as equivalent to the single
* character {@code 'b'}.
*
* </ul>
* <p>
* The specified stream remains open after this method returns.
*
* @param reader the input character stream.
* @throws IOException if an error occurred when reading from the
* input stream.
* @throws IllegalArgumentException if a malformed Unicode escape
* appears in the input.
* @since 1.6
*/
public synchronized void load(Reader reader) throws IOException {
// Reader 加载
load0(new LineReader(reader));
}

/**
* Reads a property list (key and element pairs) from the input
* byte stream. The input stream is in a simple line-oriented
* format as specified in
* {@link #load(java.io.Reader) load(Reader)} and is assumed to use
* the ISO 8859-1 character encoding; that is each byte is one Latin1
* character. Characters not in Latin1, and certain special characters,
* are represented in keys and elements using Unicode escapes as defined in
* section 3.3 of
* <cite>The Java&trade; Language Specification</cite>.
* <p>
* The specified stream remains open after this method returns.
*
* @param inStream the input stream.
* @exception IOException if an error occurred when reading from the
* input stream.
* @throws IllegalArgumentException if the input stream contains a
* malformed Unicode escape sequence.
* @since 1.2
*/
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);
}
}

/**
* Writes this property list (key and element pairs) in this
* {@code Properties} table to the output stream in a format suitable
* for loading into a {@code Properties} table using the
* {@link #load(InputStream) load(InputStream)} method.
* <p>
* Properties from the defaults table of this {@code Properties}
* table (if any) are <i>not</i> written out by this method.
* <p>
* This method outputs the comments, properties keys and values in
* the same format as specified in
* {@link #store(java.io.Writer, java.lang.String) store(Writer)},
* with the following differences:
* <ul>
* <li>The stream is written using the ISO 8859-1 character encoding.
*
* <li>Characters not in Latin-1 in the comments are written as
* {@code \u005Cu}<i>xxxx</i> for their appropriate unicode
* hexadecimal value <i>xxxx</i>.
*
* <li>Characters less than {@code \u005Cu0020} and characters greater
* than {@code \u005Cu007E} in property keys or values are written
* as {@code \u005Cu}<i>xxxx</i> for the appropriate hexadecimal
* value <i>xxxx</i>.
* </ul>
* <p>
* After the entries have been written, the output stream is flushed.
* The output stream remains open after this method returns.
* <p>
* @param out an output stream.
* @param comments a description of the property list.
* @exception IOException if writing this property list to the specified
* output stream throws an <tt>IOException</tt>.
* @exception ClassCastException if this {@code Properties} object
* contains any keys or values that are not {@code Strings}.
* @exception NullPointerException if {@code out} is null.
* @since 1.2
*/
public void store(OutputStream out, String comments)
throws IOException
{
store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
comments,
true);
}

private void store0(BufferedWriter bw, String comments, boolean escUnicode)
throws IOException
{
if (comments != null) {
writeComments(bw, comments);
}
bw.write("#" + new Date().toString());
bw.newLine();
synchronized (this) {
for (Enumeration<?> e = keys(); e.hasMoreElements();) {
String key = (String)e.nextElement();
String val = (String)get(key);
key = saveConvert(key, true, escUnicode);
/* No need to escape embedded and trailing spaces for value, hence
* pass false to flag.
*/
val = saveConvert(val, false, escUnicode);
bw.write(key + "=" + val);
bw.newLine();
}
}
bw.flush();
}

读取文本中的内容,根据特殊符号分割。保存属性内容,load 方法调用时加载出保存的数据;

XML内容加载和保存

View Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

/**
* Loads all of the properties represented by the XML document on the
* specified input stream into this properties table.
*
* <p>The XML document must have the following DOCTYPE declaration:
* <pre>
* &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
* </pre>
* Furthermore, the document must satisfy the properties DTD described
* above.
*
* <p> An implementation is required to read XML documents that use the
* "{@code UTF-8}" or "{@code UTF-16}" encoding. An implementation may
* support additional encodings.
*
* <p>The specified stream is closed after this method returns.
*
* @param in the input stream from which to read the XML document.
* @throws IOException if reading from the specified input stream
* results in an <tt>IOException</tt>.
* @throws java.io.UnsupportedEncodingException if the document's encoding
* declaration can be read and it specifies an encoding that is not
* supported
* @throws InvalidPropertiesFormatException Data on input stream does not
* constitute a valid XML document with the mandated document type.
* @throws NullPointerException if {@code in} is null.
* @see #storeToXML(OutputStream, String, String)
* @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
* Encoding in Entities</a>
* @since 1.5
*/
public synchronized void loadFromXML(InputStream in)
throws IOException, InvalidPropertiesFormatException
{
XmlSupport.load(this, Objects.requireNonNull(in));
in.close();
}

/**
* Emits an XML document representing all of the properties contained
* in this table.
*
* <p> An invocation of this method of the form <tt>props.storeToXML(os,
* comment)</tt> behaves in exactly the same way as the invocation
* <tt>props.storeToXML(os, comment, "UTF-8");</tt>.
*
* @param os the output stream on which to emit the XML document.
* @param comment a description of the property list, or {@code null}
* if no comment is desired.
* @throws IOException if writing to the specified output stream
* results in an <tt>IOException</tt>.
* @throws NullPointerException if {@code os} is null.
* @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not
* {@code Strings}.
* @see #loadFromXML(InputStream)
* @since 1.5
*/
public void storeToXML(OutputStream os, String comment)
throws IOException
{
storeToXML(os, comment, "UTF-8");
}

/**
* Emits an XML document representing all of the properties contained
* in this table, using the specified encoding.
*
* <p>The XML document will have the following DOCTYPE declaration:
* <pre>
* &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
* </pre>
*
* <p>If the specified comment is {@code null} then no comment
* will be stored in the document.
*
* <p> An implementation is required to support writing of XML documents
* that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An
* implementation may support additional encodings.
*
* <p>The specified stream remains open after this method returns.
*
* @param os the output stream on which to emit the XML document.
* @param comment a description of the property list, or {@code null}
* if no comment is desired.
* @param encoding the name of a supported
* <a href="../lang/package-summary.html#charenc">
* character encoding</a>
*
* @throws IOException if writing to the specified output stream
* results in an <tt>IOException</tt>.
* @throws java.io.UnsupportedEncodingException if the encoding is not
* supported by the implementation.
* @throws NullPointerException if {@code os} is {@code null},
* or if {@code encoding} is {@code null}.
* @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not
* {@code Strings}.
* @see #loadFromXML(InputStream)
* @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
* Encoding in Entities</a>
* @since 1.5
*/
public void storeToXML(OutputStream os, String comment, String encoding)
throws IOException
{
XmlSupport.save(this, Objects.requireNonNull(os), comment,
Objects.requireNonNull(encoding));
}
  • XML 文本读取和保存操作;
  • 使用 jdk.internal.util.xml.BasicXmlPropertiesProvider 类实现;

Properties 属性的使用

View Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

/**
* Searches for the property with the specified key in this property list.
* If the key is not found in this property list, the default property list,
* and its defaults, recursively, are then checked. The method returns the
* default value argument if the property is not found.
*
* @param key the hashtable key.
* @param defaultValue a default value.
*
* @return the value in this property list with the specified key value.
* @see #setProperty
* @see #defaults
*/
public String getProperty(String key, String defaultValue) {
String val = getProperty(key);
return (val == null) ? defaultValue : val;
}

/**
* Returns an enumeration of all the keys in this property list,
* including distinct keys in the default property list if a key
* of the same name has not already been found from the main
* properties list.
*
* @return an enumeration of all the keys in this property list, including
* the keys in the default property list.
* @throws ClassCastException if any key in this property list
* is not a string.
* @see java.util.Enumeration
* @see java.util.Properties#defaults
* @see #stringPropertyNames
*/
public Enumeration<?> propertyNames() {
Hashtable<String,Object> h = new Hashtable<>();
enumerate(h);
return h.keys();
}

/**
* Returns a set of keys in this property list where
* the key and its corresponding value are strings,
* including distinct keys in the default property list if a key
* of the same name has not already been found from the main
* properties list. Properties whose key or value is not
* of type <tt>String</tt> are omitted.
* <p>
* The returned set is not backed by the <tt>Properties</tt> object.
* Changes to this <tt>Properties</tt> are not reflected in the set,
* or vice versa.
*
* @return a set of keys in this property list where
* the key and its corresponding value are strings,
* including the keys in the default property list.
* @see java.util.Properties#defaults
* @since 1.6
*/
public Set<String> stringPropertyNames() {
Hashtable<String, String> h = new Hashtable<>();
enumerateStringProperties(h);
return h.keySet();
}

/**
* Searches for the property with the specified key in this property list.
* If the key is not found in this property list, the default property list,
* and its defaults, recursively, are then checked. The method returns
* {@code null} if the property is not found.
*
* @param key the property key.
* @return the value in this property list with the specified key value.
* @see #setProperty
* @see #defaults
*/
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;
}

/**
* Enumerates all key/value pairs in the specified hashtable
* and omits the property if the key or value is not a string.
* @param h the hashtable
*/
private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
if (defaults != null) {
defaults.enumerateStringProperties(h);
}
for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
Object k = e.nextElement();
Object v = get(k);
if (k instanceof String && v instanceof String) {
h.put((String) k, (String) v);
}
}
}
  • 属性读取,从 Hashtable 中取值;

总结

  • Properties 主要用于配置文件的加载,是线程安全的;
  • Properties 的核心功能主要有两个:
    • .properties 文本配置信息读取
    • .xml 文本配置读取
  • © 2015-2020 Andrew
  • Powered by Hexo Theme Ayer
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信