安装自定义资源包作为扩展
自定义资源包加载部分向您展示如何更改资源束的加载方式。这涉及从类ResourceBundle.Control派生一个新类,然后通过调用以下方法来检索资源束:
ResourceBundle getBundle(
String baseName,
Locale targetLocale,
ResourceBundle.Control control)
参数control
是您对ResourceBundle.Control
的实现。
java.util.spi.ResourceBundleControlProviderinterface使您可以更改以下方法加载资源束的方式:
ResourceBundle getBundle(
String baseName,
Locale targetLocale)
请注意,此版本的ResourceBundle.getBundle方法不需要ResourceBundle.Control
类的实例。 ResourceBundleControlProvider
是服务提供商interface(SPI)。 SPI 使您能够创建可扩展的应用程序,这些应用程序可以轻松扩展而无需修改其原始代码库。有关更多信息,请参见创建可扩展的应用程序。
要使用 SPI,您首先要通过实现ResourceBundleControlProvider
之类的 SPI 创建服务提供商。实现 SPI 时,请指定其将如何提供服务。 ResourceBundleControlProvider
SPI 提供的服务是在您的应用程序调用方法ResourceBundle.getBundle(String baseName, Locale targetLocale)
时获得适当的ResourceBundle.Control
实例。您将Java 扩展机制作为已安装的扩展程序打包到服务提供商。运行应用程序时,不要在 Classpath 中命名 extensions。运行时环境查找并加载这些扩展。
ResourceBundleControlProvider
SPI 的已安装实现将替换默认的ResourceBundle.Control
类(定义了默认的 Binding 包加载过程)。因此,通过ResourceBundleControlProvider
interface,您可以使用任何自定义ResourceBundle.Control
类,而无需对应用程序的源代码进行任何其他更改。另外,该interface使您无需引用任何自定义ResourceBundle.Control
类即可编写应用程序。
RBCPTest.java示例显示了如何实现ResourceBundleControlProvider
interface以及如何将其打包为已安装的扩展。此示例打包在 zip 文件RBCPTest.zip
中,由以下文件组成:
-
src
-
java.util.spi.ResourceBundleControlProvider
-
rbcp
-
lib
-
build
:包含rbcontrolprovider.jar
中打包的所有文件以及类文件RBCPTest.class
下面的步骤向您展示如何重新创建文件RBCPTest.zip
的内容,RBCPTest
示例的工作方式以及如何运行它:
1.创建 ResourceBundle.Control 类的实现。
RBCPTest.java示例使用ResourseBundle.Control
的两种实现:
-
PropertiesResourceBundleControlProvider.java:这与自定义资源包加载中定义的
ResourceBundle.Control
实现相同。 -
XMLResourceBundleControl.java:此
ResourceBundle.Control
实现使用Properties.loadFromXML方法加载基于 XML 的 Binding 包。
XML 属性文件
如使用属性文件备份 ResourceBundle部分所述,属性文件是简单的文本文件。它们在每一行上包含一个键/值对。 XML 属性文件就像属性文件一样:它们包含键值对,但它们具有 XML 结构。以下是 XML 属性文件XmlRB.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties [
<!ELEMENT properties ( comment?, entry* ) >
<!ATTLIST properties version CDATA #FIXED "1.0">
<!ELEMENT comment (#PCDATA) >
<!ELEMENT entry (#PCDATA) >
<!ATTLIST entry key CDATA #REQUIRED>
]>
<properties>
<comment>Test data for RBCPTest.java</comment>
<entry key="type">XML</entry>
</properties>
以下是等效的属性文本文件:
# Test data for RBCPTest.java
type = XML
所有 XML 属性文本文件都具有相同的结构:
- DOCTYPE 声明,用于指定文档类型定义(DTD):DTD 定义 XML 文件的结构。 注意 :您可以在 XML 属性文件中使用以下 DOCTYPE 声明:
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
导出或导入属性时,无法访问系统 URI(http://java.sun.com/dtd/properties.dtd
)。它是一个字符串,用于唯一标识 XML 属性文件的 DTD。
-
根元素
<properties>
:此元素包含所有其他元素。 -
任意数量的
<comment>
元素:这些元素用于 注解。 -
任意数量的
<entry>
元素:使用属性key
指定密钥;指定<entry>
标记之间的键值。
有关 XML 属性文件的更多信息,请参见Properties类。
2.实现 ResourceBundleControlProvider interface。
此interface包含一个方法,即ResourceBundle.Control getControl(String baseName)方法。参数baseName
是资源束的名称。在getBundle
的方法定义中,指定给定资源包名称的应返回的ResourceBundle.Control
实例。
RBCPTest
示例包含ResourceBundleControlProvider
interface的两种实现PropertiesResourceBundleControlProvider.java和XMLResourceBundleControlProvider.java。如果资源束的基本名称以resources.RBControl
开头(在此示例中,所有资源文件都包含在resources
包中),则方法PropertiesResourceBundleControlProvider.getBundle
返回PropertiesResourceBundleControl
的实例:
package rbcp;
import java.util.ResourceBundle;
import java.util.spi.ResourceBundleControlProvider;
public class PropertiesResourceBundleControlProvider
implements ResourceBundleControlProvider {
static final ResourceBundle.Control PROPERTIESCONTROL =
new PropertiesResourceBundleControl();
public ResourceBundle.Control getControl(String baseName) {
System.out.println("Class: " + getClass().getName() + ".getControl");
System.out.println(" called for " + baseName);
// Throws a NPE if baseName is null.
if (baseName.startsWith("resources.RBControl")) {
System.out.println(" returns " + PROPERTIESCONTROL);
return PROPERTIESCONTROL;
}
System.out.println(" returns null");
System.out.println();
return null;
}
}
同样,如果资源束的基本名称以resources.Xml
开头,则方法XMLResourceBundleControlProvider.getControl
返回XMLResourceBundleControl
的实例。
注意 :您可以创建ResourceBundleControlProvider
interface的一种实现,该实现根据基本名称返回PropertiesResourceBundleControl
或XMLResourceBundleControl
的实例。
3.在您的应用程序中,调用方法 ResourceBundle.getBundle。
类别RBCPTest
使用方法ResourceBundle.getBundle检索资源包:
import java.io.*;
import java.net.*;
import java.util.*;
public class RBCPTest {
public static void main(String[] args) {
ResourceBundle rb = ResourceBundle.getBundle(
"resources.XmlRB", Locale.ROOT);
String type = rb.getString("type");
System.out.println("Root locale. Key, type: " + type);
System.out.println();
rb = ResourceBundle.getBundle("resources.XmlRB", Locale.JAPAN);
type = rb.getString("type");
System.out.println("Japan locale. Key, type: " + type);
System.out.println();
test(Locale.CHINA);
test(new Locale("zh", "HK"));
test(Locale.TAIWAN);
test(Locale.CANADA);
}
private static void test(Locale locale) {
ResourceBundle rb = ResourceBundle.getBundle(
"resources.RBControl", locale);
System.out.println("locale: " + locale);
System.out.println(" region: " + rb.getString("region"));
System.out.println(" language: " + rb.getString("language"));
System.out.println();
}
}
请注意,此类中没有出现ResourceBundle.Control
或ResourceBundleControlProvider
的实现。因为ResourceBundleControlProvider
interface使用 Java 扩展机制,所以运行时环境将找到并加载这些实现。但是,使用ServiceLoader类加载了与 Java 扩展机制一起安装的ResourceBundleControlProvider
实现和其他服务提供者。使用此类意味着您必须向配置文件注册服务提供商,这将在下一步中进行描述。
4.通过创建配置文件注册服务提供商。
配置文件的名称是提供程序实现的interface或类的标准名称。配置文件包含提供程序的完全限定的类名。文件java.util.spi.ResourceBundleControlProvider包含PropertiesResourceBundleControlProvider
和XMLResourceBundleControlProvider
的完全限定名称,每行一个名称:
rbcp.XMLResourceBundleControlProvider
rbcp.PropertiesResourceBundleControlProvider
5.将提供程序,其必需的类和配置文件打包到 JAR 文件中。
编译源文件。在包含文件build.xml
的目录中,运行以下命令:
javac -d build src/java.* src/rbcp/*.java
此命令将编译src
目录中包含的源文件,并将类文件放入build
目录中。在 Windows 上,请确保使用反斜杠(\
)分隔目录和文件名。
创建一个 JAR 文件,其中包含以下目录结构中的已编译类文件,资源文件和配置文件:
-
META-INF
-
services
-
java.util.spi.ResourceBundleControlProvider
-
rbcp
-
PropertiesResourceBundleControl.class
-
PropertiesResourceBundleControlProvider.class
-
XMLResourceBundleControl.class
-
XMLResourceBundleControlProvider.class
-
-
resources
-
RBControl.properties
-
RBControl_zh.properties
-
RBControl_zh_CN.properties
-
RBControl_zh_HK.properties
-
RBControl_zh_TW.properties
-
XmlRB.xml
-
XmlRB_ja.xml
-
请注意,配置文件java.util.spi.ResourceBundleControlProvider
必须打包在目录/META-INF/services
中。此示例将这些文件打包在lib
目录的 JAR 文件rbcontrolprovider.jar
中。
有关创建 JAR 文件的更多信息,请参见JAR 文件中的打包程序。
或者,下载并安装Apache Ant,该工具使您能够自动执行构建过程,例如编译 Java 文件和创建 JAR 文件。确保 Apache Ant 可执行文件位于PATH
环境变量中,以便可以从任何目录运行它。安装 Apache Ant 后,请执行以下步骤:
-
编辑文件build.xml并将
${JAVAC}
更改为 Java 编译器的完整路径名javac
,并将${JAVA}
更改为 Java 运行时可执行文件java
的完整路径名。 -
从包含文件
build.xml
的同一目录中运行以下命令:
ant jar
此命令编译 Java 源文件,并将它们以及所需的资源和配置文件打包到lib
目录中的 JAR 文件rbcontrolprovider.jar
中。
6.运行 RBCPTest 程序。
在命令提示符处,从包含build.xml
文件的目录中运行以下命令:
java -Djava.ext.dirs=lib -cp build RBCPTest
该命令假定以下内容:
-
包含 RBCPTest 示例的已编译代码的 JAR 文件位于目录
lib
中。 -
编译后的类
RBCPTest.class
在build
目录中。
或者,使用 Apache Ant 并从包含build.xml
文件的目录中运行以下命令:
ant run
安装 Java 扩展时,通常将扩展的 JAR 文件放在 JRE 的lib/ext
目录中。但是,此命令使用系统属性java.ext.dirs
指定包含 Java 扩展的目录。
RBCPTest
程序首先try检索具有基本名称resources.XmlRB
以及语言环境Locale.ROOT
和Local.JAPAN
的资源包。检索这些资源束的程序的输出类似于以下内容:
Class: rbcp.XMLResourceBundleControlProvider.getControl
called for resources.XmlRB
returns rbcp.XMLResourceBundleControl@16c1857
Root locale. Key, type: XML
Class: rbcp.XMLResourceBundleControlProvider.getControl
called for resources.XmlRB
returns rbcp.XMLResourceBundleControl@16c1857
Japan locale. Key, type: Value from Japan locale
该程序成功获取XMLResourceBundleControl
的实例,并访问属性文件XmlRB.xml
和XmlRB_ja.xml
。
RBCPTest
程序try检索资源束时,它将调用配置文件java.util.spi.ResourceBundleControlProvider
中定义的所有类。例如,当程序检索基本名称为resources.RBControl
且语言环境为Locale.CHINA
的资源包时,它将输出以下输出:
Class: rbcp.XMLResourceBundleControlProvider.getControl
called for resources.RBControl
returns null
Class: rbcp.PropertiesResourceBundleControlProvider.getControl
called for resources.RBControl
returns rbcp.PropertiesResourceBundleControl@1ad2911
locale: zh_CN
region: China
language: Simplified Chinese