The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
The section Customizing Resource Bundle Loading shows you how to change how resource bundles are loaded. This involves deriving a new class from the class ResourceBundle.Control, then retrieving the resource bundle by invoking the following method:
ResourceBundle getBundle( String baseName, Locale targetLocale, ResourceBundle.Control control)
The parameter control is your implementation of ResourceBundle.Control.
The java.util.spi.ResourceBundleControlProvider interface enables you to change how the following method loads resource bundles:
ResourceBundle getBundle( String baseName, Locale targetLocale)
Note that this version of the ResourceBundle.getBundle method does not require an instance of the ResourceBundle.Control class. ResourceBundleControlProvider is a service provider interface (SPI). SPIs enable you to create extensible applications, which are those that you can extend easily without modifying their original code base. See Creating Extensible Applications for more information.
To use SPIs, you first create a service provider by implementing an SPI like ResourceBundleControlProvider. When you implement an SPI, you specify how it will provide the service. The service that the ResourceBundleControlProvider SPI provides is to obtain an appropriate ResourceBundle.Control instance when your application invokes the method ResourceBundle.getBundle(String baseName, Locale targetLocale). You package the service provider with the Java Extension Mechanism as an installed extension. When you run your application, you do not name your extensions in your class path; the runtime environment finds and loads these extensions.
An installed implementation of the ResourceBundleControlProvider SPI replaces the default ResourceBundle.Control class (which defines the default bundle loading process). Consequently, the ResourceBundleControlProvider interface enables you to use any of the custom ResourceBundle.Control classes without any additional changes to the source code of your application. In addition, this interface enables you to write applications without having to refer to any of your custom ResourceBundle.Control classes.
The sample shows how to implement the RBCPTest.javaResourceBundleControlProvider interface and how to package it as an installed extension. This sample, which is packaged in the zip file , consists of the following files:RBCPTest.zip
src java.util.spi.ResourceBundleControlProviderRBCPTest.javarbcp resources lib build: Contains all files packaged in rbcontrolprovider.jar as well as the class file RBCPTest.classbuild.xmlThe following steps show you how to re-create the contents of the file RBCPTest.zip, how the RBCPTest sample works, and how to run it:
The sample uses two implementations of RBCPTest.javaResourseBundle.Control:
: This is the same PropertiesResourceBundleControlProvider.javaResourceBundle.Control implementation that is defined in Customizing Resource Bundle Loading.
: This XMLResourceBundleControl.javaResourceBundle.Control implementation loads XML-based bundles with the method Properties.loadFromXML.
As described in the section Backing a ResourceBundle with Properties Files, properties files are simple text files. They contain one key-value pair on each line. XML properties files are just like properties files: they contain key-value pairs except they have an XML structure. The following is the XML properties file 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>
The following is the properties text file equivalent:
# Test data for RBCPTest.java type = XML
All XML properties text files have the same structure:
A DOCTYPE declaration that specifies the Document Type Definition (DTD): The DTD defines the structure of an XML file. Note: You can use the following DOCTYPE declaration instead in an XML properties file:
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
The system URI (http://java.sun.com/dtd/properties.dtd) is not accessed when exporting or importing properties; it is a string that uniquely identifies the DTD of XML properties files.
Root element <properties>: This element contains all the other elements.
Any number of <comment> elements: These are used for comments.
Any number of <entry> elements: Use the attribute key to specify the key; specify the value of the key between the <entry> tags.
See the Properties class for more information about XML properties files.
This interface contains one method, the ResourceBundle.Control getControl(String baseName) method. The parameter baseName is the name of the resource bundle. In the method definition of getBundle, specify the instance of ResourceBundle.Control that should be returned given the name of the resource bundle.
The RBCPTest sample contains two implementations of the ResourceBundleControlProvider interface, and PropertiesResourceBundleControlProvider.java. The method XMLResourceBundleControlProvider.javaPropertiesResourceBundleControlProvider.getBundle returns an instance of PropertiesResourceBundleControl if the base name of the resource bundle starts with resources.RBControl (in this example, all the resource files are contained in the package resources):
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;
}
}
Similarly, the method XMLResourceBundleControlProvider.getControl returns an instance of XMLResourceBundleControl if the base name of the resource bundle starts with resources.Xml.
Note: You can create one implementation of the ResourceBundleControlProvider interface that returns either an instance of PropertiesResourceBundleControl or XMLResourceBundleControl depending on the base name.
The class RBCPTest retrieves resource bundles with the method 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();
}
}
Note that no implementations of ResourceBundle.Control or ResourceBundleControlProvider appear in this class. Because the ResourceBundleControlProvider interface uses the Java Extension Mechanism, the runtime environment finds and loads these implementations. However, ResourceBundleControlProvider implementations and other service providers that are installed with the Java Extension Mechanism are loaded using the ServiceLoaderclass. Using this class means that you have to register the service provider with a configuration file, which is described in the next step.
The name of the configuration file is the fully qualified name of the interface or class that the provider implemented. The configuration file contains the fully qualified class name of your provider. The file contains the fully qualified names of java.util.spi.ResourceBundleControlProviderPropertiesResourceBundleControlProvider and XMLResourceBundleControlProvider, one name per line:
rbcp.XMLResourceBundleControlProvider rbcp.PropertiesResourceBundleControlProvider
Compile the source files. From the directory that contains the file build.xml, run the following command:
javac -d build src/java.* src/rbcp/*.java
This command will compile the source files contained in the src directory and put the class files in the build directory. On Windows, ensure that you use the backslash (\) to separate directory and file names.
Create a JAR file that contains the compiled class files, resource files, and the configuration file in the following directory structure:
META-INF services java.util.spi.ResourceBundleControlProviderrbcp PropertiesResourceBundleControl.classPropertiesResourceBundleControlProvider.classXMLResourceBundleControl.classXMLResourceBundleControlProvider.classresources RBControl.propertiesRBControl_zh.propertiesRBControl_zh_CN.propertiesRBControl_zh_HK.propertiesRBControl_zh_TW.propertiesXmlRB.xmlXmlRB_ja.xmlNote that the configuration file java.util.spi.ResourceBundleControlProvider must be packaged in the directory /META-INF/services. This sample packages these files in the JAR file rbcontrolprovider.jar in the lib directory.
See Packaging Programs in JAR Files for more information about creating JAR files.
Alternatively, download and install Apache Ant, which is a tool that enables you to automate build processes, such as compiling Java files and creating JAR files. Ensure that the Apache Ant executable file is in your PATH environment variable so that you can run it from any directory. Once you have installed Apache Ant, follow these steps:
Edit the file and change build.xml${JAVAC} to the full path name of your Java compiler, javac, and ${JAVA} to the full path name of your Java runtime executable, java.
Run the following command from the same directory that contains the file build.xml:
ant jar
This command compiles the Java source files and packages them, along with the required resource and configuration files, into the JAR file rbcontrolprovider.jar in the lib directory.
At a command prompt, run the following command from the directory that contains the build.xml file:
java -Djava.ext.dirs=lib -cp build RBCPTest
This command assumes the following:
lib.RBCPTest.class, is in the build directory.Alternatively, use Apache Ant and run the following command from the directory that contains the build.xml file:
ant run
When you install a Java extension, you typically put the JAR file of the extension in the lib/ext directory of your JRE. However, this command specifies the directory that contains Java extensions with the system property java.ext.dirs.
The RBCPTest program first attempts to retrieve resource bundles with the base name resources.XmlRB and the locales Locale.ROOT and Local.JAPAN. The output of the program retrieving these resource bundles is similar to the following:
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
The program successfully obtains an instance of XMLResourceBundleControl and accesses the properties files XmlRB.xml and XmlRB_ja.xml.
When the RBCPTest program tries to retrieve a resource bundle, it calls all the classes defined in the configuration file java.util.spi.ResourceBundleControlProvider. For example, when the program retrieves the resource bundle with the base name resources.RBControl and the locale Locale.CHINA, it prints the following output:
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