早期 Java 專案常用類 Windows INI 格式的 .properties 檔案管理配置,隨著 Tomcat、J2EE 標準配置文件全面採用 XML,XML 以其結構化、可擴展、支援命名空間與驗證等優勢成為事實標準。本文示範如何使用 SAX 解析器高效讀取 XML 配置文件。
<myenv>
<datasource>
<dbhost>localhost</dbhost>
<dbname>sqlname</dbname>
<dbuser>username</dbuser>
<dbpassword>password</dbpassword>
</datasource>
</myenv>
檔案通常放置於 WEB-INF/classes 目錄,便於類別載入器尋找。
| 特性 | SAX | DOM |
|---|---|---|
| 解析方式 | 事件驅動、流式讀取 | 一次性載入記憶體建立樹 |
| 記憶體佔用 | 極低,適合大文件 | 較高,受限於記憶體 |
| 隨機存取 | 不支援 | 支援完整樹狀導航 |
| 適用場景 | 配置文件、日誌、大型數據交換 | 需頻繁修改結構的小型文檔 |
配置文件通常較小且單向讀取,SAX 是理想選擇。本文基於 JDK 1.4+ 環境,使用 javax.xml.parsers 標準 API。
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.Properties;
public class ConfigParser extends DefaultHandler {
private Properties props = new Properties();
private String currentName;
private StringBuffer currentValue = new StringBuffer();
public Properties getProps() { return props; }
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
currentValue.setLength(0); // 清空緩衝區
this.currentName = qName;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
currentValue.append(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
props.put(qName.toLowerCase(), currentValue.toString().trim());
}
}
設計要點:
DefaultHandler 避免實作所有介面方法。StringBuffer 累積字符數據,應對 SAX 可能分多次回調 characters() 的情況。Properties,鍵統一轉小寫便於後續不區分大小寫查詢。import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.net.URL;
import java.util.Properties;
public class ParseXML {
private Properties props;
public Properties getProps() { return props; }
public void parse(String filename) throws Exception {
ConfigParser handler = new ConfigParser();
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(false);
factory.setValidating(false); // 配置文件通常無需 DTD/Schema 驗證
SAXParser parser = factory.newSAXParser();
// 透過類別載入器定位資源,支援 WAR 部署與單元測試
URL confURL = ParseXML.class.getClassLoader().getResource(filename);
if (confURL == null) throw new RuntimeException("配置文件未找到: " + filename);
try {
parser.parse(confURL.toString(), handler);
props = handler.getProps();
} finally {
// 釋放引用協助 GC
factory = null;
parser = null;
handler = null;
}
}
}
public class TestConfig {
public static void main(String[] args) throws Exception {
ParseXML parser = new ParseXML();
parser.parse("myenv.xml");
Properties props = parser.getProps();
System.out.println("dbhost: " + props.getProperty("dbhost"));
System.out.println("dbuser: " + props.getProperty("dbuser"));
System.out.println("dbpassword: " + props.getProperty("dbpassword"));
}
}
<dbhost ip="192.168.1.1">),可在 startElement 中透過 Attributes 參數讀取。setNamespaceAware(true) 後,localName 與 qName 需正確區分。ErrorHandler 介面捕獲解析錯誤與警告。SAX 解析器以流式、事件驅動特性完美契合配置文件讀取需求。結合 DefaultHandler 簡化開發,搭配類別載入器資源定位機制,即可構建健壯、可部署的配置管理模組。此模式易於擴展支援多環境配置(dev/test/prod)、屬性加密解密等企業級需求。