为什么选择Prop替代Java Properties?探索其UTF-8支持与兼容性优势

[id_1526084480]id_1655684926]

为什么选择Prop替代Java Properties?探索其UTF-8支持与兼容性优势

属性被存储在一个或者多个*.props 文件中。它是开放的,能够支持多种类型的资源。并且,它与 java properties 是兼容的。

Props 的目标并非提供一个能最大限度进行配置的解决方案,而是提供一个相较于 java properties 更优的选择。所以倘若在应用中用到了 properties,那就可以考虑用 Props 去替代它。

基本规则

3. 这里有介绍 props 文件格式的一组基本规则,部分规则示例如下:

utf8编码

通常情况下,props 文件的编码为 utf8,同时也能够使用其他任何一种编码格式。无论采用何种编码格式,在 props 加载 java properites 时,依然会使用 ISO 8859-1。

去除空白字符

分区名称的开头结尾空白字符将被去除,属性名称的开头结尾空白字符也将被去除,同时属性值的开头和结尾空白字符也会被去除。

赋值

可以使用"="或者":"进行赋值。

值连接

使用"+="连接同名属性的值(以逗号分隔)。

注解

从";"或者"#"开头到行的结尾来注解。

转义符

使用"\"来作为转义符,对字符进行转义操作。比如"\#"就代表了字符"#",而"\\"则代表着"\"。

多行的值(Multi-line values)

如果"\"作为行的连接符,表明下一行仍然是属性的值。

特殊字符

\(\\uXXXX\)会被编译成字符,并且\(\t\)会被编译成字符,\(\r\)会被编译成字符,\(\f\)也会被编译成字符。

多行值(Multiline values)

使用三引号作为一种方便的形式来定义多行的值。

请提供需要改写的句子呀,你没有给出具体的内容呢。

三引号使程序员摆脱了引号和特殊字符串的困扰,始终能保持一小块字符串为所谓的 WYSIWYG(所见即所得)格式。

基本用法

Props的使用非常简单。概况的说,Props管理着属性。

    Props p = new Props();
    p.load(new File("example.props"));
    ...
    String story = p.getValue("story");

Props 加载属性有多种形式,包括文件、输入流、字符串以及属性 Properties。接着可以通过 Props 的 setValue 方法来调用属性值,此方法一般会返回一个字符串的值。

分区

分区与 INI 文件的分区很相似。在 Props 里,分区仅仅意味着一组键,这组键的前缀是相同的,并且会一直延续到分区结束或者文件结束。

分区名称开头和结尾。该分区的属性在头部之后。分区名称会加到分区属性前。分区以空的[]结尾或新分区开始或到文件尾部。

示例如下:

[users.data]
weight = 49.5
height = 87.7
age = 63
[]
comment=this is base property

下面的和上述示例等同:

users.data.weight = 49.5
users.data.height = 87.7
users.data.age = 63
comment=this is base property

因此,分区可以缩短文件,从而使文件更可读。

Profiles

一般来讲,一个应用具备不同的环境,所以需要不同组别的属性。像 web 应用的测试环境和发布环境就是这样的例子。一种对这些属性进行组织的方式是定义不同的 profile,在这些 profile 中,相同的键会有不同的值。

Props 能够支持属性的 Profile。Profile 是在键名内进行定义的:用包装来包裹 profile 名称。一个可以具有一个或者多个 profile 的定义。同样地,profile 可以在键名的任何位置进行定义,甚至在单词的中间;不过,最好是将其放置在键名的尾部。

属性分为基于 profile 的和没有 profile 的。如果检索特定 profile 的属性不成功,那么就会去检查基本的属性。

profile 能够被视为相同属性组的一个“不同的视角”或者“瞬间记录”。例如:

db.port=3086
db.url=localhost
db.username=root
db.url=192.168.1.101
db.username=app2499

在上述示例里,定义了 3 个键。其中有两个键具备两个不同的 profile,分别是 develop 和 deploy,并且这两个键没有基本的值。

上文提到,分区是键的前缀定义。同时,profile 能定义在键名的任意位置。正因如此,分区名称也可以包含 profile 定义。上述的示例可以进行如下改造:

db.port=3086
[db]
url=localhost
username=root
[db]
url=192.168.1.101
username=app2499

当检索上述值时,可以指定活跃的profile:

获取属性值,属性名为"db.url",若未找到则使用"develop",将其赋值给字符串变量 url 。;
获取属性"db.username"的值,如果没有则默认为"develop",并将其赋值给字符串变量 user;

一个 profile 能够多次被同时定义。profile 的顺序有着重要意义!若键被定义到多个处于活跃状态的 profile 时,就会返回第一个 profile 的值(第一个匹配的 profile 的值)。

你可以仅检索基本属性,并且忽略 profile。可以使用 getBaseValue()方法来进行检索。基本属性不属于任何 profile。

默认的活跃profile

通常,在一个应用的生命周期里,仅有一组 profile 是处于活跃状态的。不需要每次在调用 getValues()的时候都去传递这组活跃的 profile。Props 能够在外部对这个所谓的活跃 profile 进行定义,并且这个定义是在加载属性的 props 文件当中的。

在使用 getValue(String) 来检索属性的时候,默认的 profile 就是活跃的 profile。活跃的 profile 是通过 @profiles 的特殊属性键来定义的。例如:

key1=hello
key1=Hi!
@profiles=one

则下面的java代码:

获取属性值的操作,将其赋值给了 String 类型的变量 value ,具体的属性名为 props.getValue( 中的内容 。"key1");

将会返回值“Hi!”,因为活跃profile是"one".

活跃 profile 能够通过 java 代码来进行设置,其方法为:设置活跃的 profiles 。

内部profile

存在这样一种情景:两个或者多个 profile 具备大部分相同的配置,仅仅只有一小部分属性是不一样的。为了防止在每一个 profile 里都重复去定义所有的属性,能够运用内部 profile 来明确哪些是不同的属性。Props 首先会去查找内部 profile 的键,接着再去查找基本属性,以下是示例:

key1=Hi!
key2=...
....
key100=...
key1=Hola!

上述示例定义了两个 profiles 。其中第一个 profile 的名称为“one”,此 profile 包含 100 个键值对。第二个 profile 是一个内部 profile ,其名称为 one.two 。这个内部 profile 包含一个属性(key1),并且上层 profile 的所有属性都是可用的。使用 java 代码去调用上述属性,即调用 props.getValue("key1", "one.two")时,会出现怎样的情况呢?

Props将会

在内部名为one.two的profile中检索属性

如果没有找到,那么就对 Props 进行检查,检查上一层的 profile:one。

如果检索不到,且没有更高级别的 profile 了,那么 Props 就会检索基本属性。

内部profile可用有很多层。

宏

Props 的一个重要优点在于它支持宏。宏指的是一些键值的引用,其他的键能够使用这些值。宏是用{}来包装的。以下是一个示例:

key1=Something ${foo}
...
foo=nice

key1 的值为“Something nice”。宏能够引用任何已存在的属性键,无论这些属性键在何处定义。

同样也支持嵌套的宏,示例如下:

key1=**${key${key3}}**
key3=2
key2=foo

key1的值是"**foo**".

宏和profile

宏一般会利用当前处于活跃状态或者被提供的 profile 进行解析。如果当前的 profile 发生了改变,那么宏的值通常也会随之改变。

这种行为是由标志位 useActiveProfilesWhenResolvingMacros 来进行控制的。以下是一些例子:

root=/app
root=/foo
data.path=${root}/data

当 profile 设置为 active 时,data.path 的值是多少?因为 foo 处于活跃状态,所以 root 的值变成了/foo,进而 data.path 的值为/foo/data.

如果我们将所有的 profile 都关闭,只使用基本属性,那么 data.path 的值就是 /app/data.

也可以显示的设置宏的profile:

root=/app
root=/foo
data.path=${root}/data

在上述例子里,宏 root 会始终使用 foo profile,不管当前选定的是哪个 profile。所以,data.path 的值会一直是“/foo/data”。

多行值

多行的值可以通过三引号定义。中间的都看做值:

email.body='''
    Hello $n,
    welcome!
'''

注意:多行的值的空白不会对剪短产生影响!所以上述示例中的值会包含 5 行。

遍历和键的顺序

Props 中的键是有顺序的。所以能够依据属性文件中键的顺序来遍历所有的键。无需使用如下代码。

foo.1=value1
foo.2=value2
...

你可以遍历props如下:

 Props props = ....
 Iterator it = p.iterator();

遍历的顺序和props定义的顺序一致。

可以通过增加 profile 来进行过滤检索,也可以通过增加 profile 来进行分区遍历,或者同时进行这两种操作。

    Iterator it = p.entries()
            .section("one.two")
            .profile("prof1", "prof2")
            .iterator();

上述代码仅仅遍历给定分区和给定profile的属性。

因为引入了 profile,所以能够将一个键定义在属性文件的多个位置。比如,你可以给两个不同的 profile 定义一个特定的值。在这种情形下,无法确定键的正确顺序,即不知道是最先检索到的键,还是它所在位置获取的值。你能够利用 skipDuplicatesByValue 以及 skipDuplicatesByPosition() 进行控制。

复制操作符

假定你拥有一定数量的属性,在默认情况下,这个数量与不同种类的数目是相同的,示例情况如下:

com.jodd.action1=value1
com.jodd.action2=value2
...
org.jodd.action1=value1
org.jodd.action2=value2
...
net.jodd.... # etc

Props支持你使用复制操作符(

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

25阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

25阅读