java由JABXContext注解讀取xml配置文件方式
1. 本篇內(nèi)容
在用java作開(kāi)發(fā)時(shí),一般會(huì)選擇使用xml文件作為配置文件,故而通過(guò)java工程讀取配置文件則是必須掌握的知識(shí);
傳統(tǒng)的C/C++通過(guò)File文件的方式或者說(shuō)通過(guò)流的方式進(jìn)行讀寫,過(guò)分的浪費(fèi)內(nèi)存與效率,且讀寫及其不方便,不適用于java的靈活配置,而java的注解方式成功的解決了該問(wèn)題。
作者在從事相關(guān)的開(kāi)發(fā)中學(xué)習(xí)了一下注解的方式,并成功開(kāi)發(fā)了項(xiàng)目;雖然現(xiàn)在網(wǎng)上關(guān)于此知識(shí)已經(jīng)鋪天蓋地,而我仍舊希望將自己的經(jīng)驗(yàn)與大家分享。
2. 選擇要讀取的配置文件
下面的配置文件雖說(shuō)是作者編纂,但仍可代表一般的配置,讀者姑妄觀之,見(jiàn)下
<?xml version="1.0" encoding="UTF-8"?> <cham formatversion="1.14"> ? <servers> ? ? <centers> ?? ? ?<center id="1" name="center1"> ?? ? ? ?<main> ?? ??? ? ?<iphost>127.0.0.1</iphost> ?? ??? ? ?<port>8443</port> ?? ??? ? ?<byte-sequence>BigEndian</byte-sequence> ?? ??? ?</main> ?? ??? ?<preparation> ?? ??? ? ?<iphost>10.10.10.1</iphost> ?? ??? ? ?<port>8080</port> ?? ??? ? ?<byte-sequence>BigEndian</byte-sequence> ?? ??? ?</preparation> ?? ??? ?<argument-ref>ccsArg</argument-ref> ?? ? ?</center> ?? ?</centers> ? </servers> </cham>
上文中的配置文件格式是標(biāo)準(zhǔn)的配置文件格式,配置文件中其實(shí)只包含了一個(gè)數(shù)組,記<centers></centers>節(jié)點(diǎn),而我們此次的主要目的也是講解該節(jié)點(diǎn)。
3. 基本注解講解
從嚴(yán)格意義上來(lái)講,XML文件常用的注解共有四個(gè):
1) @XmlRootElement(name="") 用于注解根節(jié)點(diǎn),即XML的起點(diǎn)
2)@XmlAttribute(name="") 用于注釋attribute,例如<center id="1" name="center1"/>中的id和name兩個(gè)屬性
2)@XmlElement(name="") 最常用的注釋方式,用于注釋節(jié)點(diǎn),例如<port>8080</port>
4)@XmlTransient 用于放置在get方法上,放置報(bào)錯(cuò)。
4. java相應(yīng)文件的寫作
分析上述的cham.xml配置文件,很容易產(chǎn)清楚它的結(jié)構(gòu),它有以下幾個(gè)部分組成
1. cham.xml文件由一個(gè)<servers/>節(jié)點(diǎn)組成
2. servers節(jié)點(diǎn)由<centers/>節(jié)點(diǎn)組成,而<centers/>節(jié)點(diǎn)是個(gè)數(shù)組,用于可以在其中配置多個(gè)<center/>,而本帖中只包含了一個(gè)元素。
3. <center/>節(jié)點(diǎn)由兩部分組成,即<main/><preparation/> 和 <argument-ref/>節(jié)點(diǎn)。
我們的分析方式采用的由內(nèi)及外的讀取方式
4.1 最基本的<main/>單元
查看上述cham.xml文件,則可以發(fā)現(xiàn)<main/>和<preparation/>是最基本的配置單元,沒(méi)有比它更小的單元了,我們不妨先從它開(kāi)始注解
我們可以建立一個(gè)名字叫做ServerPoint.java的文件來(lái)表示該節(jié)點(diǎn)
package com.china.domain.config;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
public class ServerPoint implements Serializable {
?? ?private static final long serialVersionUID = 3623939598540009923L;
?? ?@XmlElement(name="iphost")
?? ?private String iphost;
?? ?@XmlElement(name="port")
?? ?private int port;
?? ?@XmlElement(name="byte-sequence")
?? ?private String byteSequence;
?? ?@XmlTransient
?? ?public String getIphost() {
?? ??? ?return iphost;
?? ?}
?? ?public void setIphost(String iphost) {
?? ??? ?this.iphost = iphost;
?? ?}
?? ?@XmlTransient
?? ?public int getPort() {
?? ??? ?return port;
?? ?}
?? ?public void setPort(int port) {
?? ??? ?this.port = port;
?? ?}
?? ?@XmlTransient
?? ?public String getByteSequence() {
?? ??? ?return byteSequence;
?? ?}
?? ?public void setByteSequence(String byteSequence) {
?? ??? ?this.byteSequence = byteSequence;
?? ?}
?? ?@Override
?? ?public String toString() {
?? ??? ?return " [iphost=" + iphost + ", port=" + port + ", byteSequence=" + byteSequence + "]";
?? ?}
}讀者很容易看出來(lái),該文件和之前<main/>或者<preparation/>節(jié)點(diǎn)的內(nèi)容正好一一對(duì)應(yīng)。所涉及的注釋有兩個(gè),即@XmlElement 和 @XmlTransient,它們的功能此處不再贅述。
4.2 <center/>節(jié)點(diǎn)講解
從之前的分析可以知道,<center/>節(jié)點(diǎn)共包含兩個(gè)部分或者說(shuō)三個(gè)部分,即<main/><preparation/>和 <argument-ref/>節(jié)點(diǎn)。從內(nèi)容上看,需要用到的注釋有三個(gè),即@XmlElement 、@XmlAttribute 、@XmlTransient
我們可以用一個(gè)Center.java 文件來(lái)表示該節(jié)點(diǎn),如下所示:
package com.china.domain.config;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
public class Center implements Serializable {
?? ?private static final long serialVersionUID = 4568925940918840647L;
?? ?@XmlAttribute(name="id")
?? ?private int id;
?? ?@XmlAttribute(name="name")
?? ?private String name;
?? ?@XmlElement(name="main")
?? ?private ServerPoint serverPoint;
?? ?@XmlElement(name="preparation")
?? ?private ServerPoint back;
?? ?@XmlElement(name="argument-ref")
?? ?private String argumentRef;
?? ?@XmlTransient
?? ?public int getId() {
?? ??? ?return id;
?? ?}
?? ?public void setId(int id) {
?? ??? ?this.id = id;
?? ?}
?? ?@XmlTransient
?? ?public String getName() {
?? ??? ?return name;
?? ?}
?? ?public void setName(String name) {
?? ??? ?this.name = name;
?? ?}
?? ?@XmlTransient
?? ?public ServerPoint getServerPoint() {
?? ??? ?return serverPoint;
?? ?}
?? ?public void setServerPoint(ServerPoint serverPoint) {
?? ??? ?this.serverPoint = serverPoint;
?? ?}
?? ?@XmlTransient
?? ?public ServerPoint getBack() {
?? ??? ?return back;
?? ?}
?? ?public void setBack(ServerPoint back) {
?? ??? ?this.back = back;
?? ?}
?? ?@XmlTransient
?? ?public String getArgumentRef() {
?? ??? ?return argumentRef;
?? ?}
?? ?public void setArgumentRef(String argumentRef) {
?? ??? ?this.argumentRef = argumentRef;
?? ?}
?? ?@Override
?? ?public String toString() {
?? ??? ?return "Center [id=" + id + ", name=" + name + ", serverPoint=" + serverPoint + ", back=" + back
?? ??? ??? ??? ?+ ", argumentRef=" + argumentRef + "]";
?? ?}
}從上文中可以看出,用@XmlAttribute可以注釋<center id="1" name="center1"/>的場(chǎng)景,由于代碼和注釋一一匹配,此處不再多言。
4.3 <servers/>節(jié)點(diǎn)及數(shù)組的注釋方式
前面分析已知:<servers/>節(jié)點(diǎn)下是一個(gè)包含了多個(gè)(本例中只有一個(gè))<center/>的<centers/>數(shù)組,則我們創(chuàng)建和<servers/>節(jié)點(diǎn)相對(duì)應(yīng)的java文件時(shí)要考慮數(shù)組的因素。
一般來(lái)講,我們是通過(guò)@XmlElementWrapper 來(lái)注釋數(shù)組,用法如下
package com.china.domain.config;
import java.io.Serializable;
import java.util.Arrays;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlTransient;
public class Servers implements Serializable {
?? ?private static final long serialVersionUID = 8836963744878452510L;
?? ?@XmlElementWrapper(name="centers")//用于注釋<centers/>數(shù)組,表示這是個(gè)數(shù)組
?? ?@XmlElement(name="center")//用于注釋數(shù)組的子元素
?? ?private Center[] centers;
?? ?@XmlTransient
?? ?public Center[] getCenters() {
?? ??? ?return centers;
?? ?}
?? ?public void setCenters(Center[] centers) {
?? ??? ?this.centers = centers;
?? ?}
?? ?@Override
?? ?public String toString() {
?? ??? ?return " [centers=" + Arrays.toString(centers) + "]";
?? ?}
}4.4 注釋根節(jié)點(diǎn)
XML注釋中有 @XmlRootElement(name="cham")注釋根節(jié)點(diǎn),其中 cham是xml文件根節(jié)點(diǎn)的名稱,在本例中的name,即<cham formatversion="1.14"/>中的cham
用@XmlAccessorType(XmlAccessType.FIELD)注解表示當(dāng)前所注解內(nèi)容的類型,除FIELD以外還有其他數(shù)種,但最長(zhǎng)用的是FIELD,至于其他的含義,讀者請(qǐng)搜索相關(guān)資料。
我們可以創(chuàng)建一個(gè)名字叫做 SystemConfig.java的文件來(lái)存放該內(nèi)容:
package com.china.domain.config;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="cham")
public class SystemConfig implements Serializable {
?? ?private static final long serialVersionUID = -7667130896271777648L;
?? ?@XmlAttribute(name="formatversion")
?? ?private String formatVersion;
?? ?@XmlElement(name="servers")
?? ?private Servers servers;
?? ?@XmlTransient
?? ?public String getFormatVersion() {
?? ??? ?return formatVersion;
?? ?}
?? ?public void setFormatVersion(String formatVersion) {
?? ??? ?this.formatVersion = formatVersion;
?? ?}
?? ?@XmlTransient
?? ?public Servers getServers() {
?? ??? ?return servers;
?? ?}
?? ?public void setServers(Servers servers) {
?? ??? ?this.servers = servers;
?? ?}
?? ?@Override
?? ?public String toString() {
?? ??? ?return "SystemConfig {formatVersion=" + formatVersion + ", servers=" + servers + "}";
?? ?}
}至此,注解部分已經(jīng)完成。
5. XML文件的位置
一般來(lái)講,無(wú)論C/C++還是java,都會(huì)將配置文件放置在工程的某個(gè)目錄之下。由于作者開(kāi)發(fā)中使用到了tomcat容器,根據(jù)習(xí)慣,故將配置文件放置在tomacat下的/conf/目錄下
java提供 getProperty 方法獲取/conf/上層路徑,即我們可以通過(guò) String configPath = System.getProperty("catalina.base"); 方式來(lái)獲取到/conf/的路徑,其中catalina.base即為/conf/上層路徑,讀者可以查看相關(guān)tomcat文檔中的定義
6. 分隔符的講解
該部分是作者在開(kāi)發(fā)過(guò)程中碰到的一個(gè)小陷阱,特拿出來(lái)和大家分享;作者在獲取到路徑后卻始終不能讀取文件,后來(lái)發(fā)現(xiàn)是缺少分隔符
我們可以通過(guò)如下代碼獲取/conf/路徑并添加分隔符
if(!this.configPath.endsWith(File.separator)) {
?? ??? ??? ?this.configPath = this.configPath + File.separatorChar + "conf" + File.separatorChar;
?? ??? ?}else {
?? ??? ??? ?this.configPath = this.configPath + "conf" + File.separatorChar;
?? ??? ?}如果我們?cè)賱?chuàng)建一個(gè) configFile變量來(lái)存儲(chǔ)cham.xml文件,則configFile=configPath+"cham.xml";
7.java中讀取xml注解的方式
這段代碼比較固定,讀者可以再網(wǎng)上任意搜到
package com.china.domain.comm.basicread;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import javax.xml.bind.JAXBContext;
import org.xml.sax.InputSource;
import com.china.domain.config.SystemConfig;
import javax.xml.bind.Unmarshaller;
public class XmlReaders {
?? ?private String configPath;
?? ?private String configFile;
?? ?private SystemConfig config;
?? ?public XmlReaders(String configPath) {
?? ??? ?super();
?? ??? ?this.configPath = configPath;
?? ??? ?initConfigPath();
?? ??? ?initSystemConfig();
?? ?}
?? ?private void initConfigPath() {
?? ??? ?if(null == this.configPath) {
?? ??? ??? ?System.out.println("configPath is null");
?? ??? ??? ?return;
?? ??? ?}
?? ??? ?if(!this.configPath.endsWith(File.separator)) {
?? ??? ??? ?this.configPath = this.configPath + File.separatorChar + "conf" + File.separatorChar;
?? ??? ?}else {
?? ??? ??? ?this.configPath = this.configPath + "conf" + File.separatorChar;
?? ??? ?}
?? ??? ?this.configFile = this.configPath + "cham.xml";
?? ?}
?? ?private void initSystemConfig() {
?? ??? ?if(null == this.configFile) {
?? ??? ??? ?System.out.println("configFile is null");
?? ??? ??? ?return;
?? ??? ?}
?? ??? ?try {
?? ??? ? ? ?JAXBContext context = JAXBContext.newInstance(SystemConfig.class);//首先創(chuàng)建SystemConfig.java的模型
?? ??? ? ? ?Unmarshaller umar = context.createUnmarshaller();
?? ??? ? ? ?File file = new File(this.configFile);
?? ??? ? ? ?InputStream inputStream = new FileInputStream(file);//通過(guò)輸入流讀取配置文件
?? ??? ? ? ?InputSource source = new InputSource(inputStream);
?? ??? ? ? ?source.setEncoding("UTF-8");//設(shè)置讀取字節(jié)的方式
?? ??? ? ? ?this.config = (SystemConfig)umar.unmarshal(inputStream);
?? ??? ?}catch(Exception e) {
?? ??? ??? ?System.out.println("Exceptions : " + e.toString());
?? ??? ?}
?? ?}
?? ?public String getConfigPath() {
?? ??? ?return configPath;
?? ?}
?? ?public void setConfigPath(String configPath) {
?? ??? ?this.configPath = configPath;
?? ?}
?? ?public String getConfigFile() {
?? ??? ?return configFile;
?? ?}
?? ?public void setConfigFile(String configFile) {
?? ??? ?this.configFile = configFile;
?? ?}
?? ?public SystemConfig getConfig() {
?? ??? ?return config;
?? ?}
?? ?public void setConfig(SystemConfig config) {
?? ??? ?this.config = config;
?? ?}
}只要調(diào)用XmlReaders.java這個(gè)類的構(gòu)造函數(shù),則可以成功的將配置文件讀取到SystemConfig.java類中
8.結(jié)果展示
SystemConfig = SystemConfig {formatVersion=1.14, servers= [centers=[Center [id=1, name=center1, serverPoint= [iphost=127.0.0.1, port=8443, byteSequence=BigEndian], back= [iphost=10.10.10.1, port=8080, byteSequence=BigEndian], argumentRef=ccsArg]]]}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
IntelliJ IDEA使用教程從入門到上癮(2019圖文版)
這篇文章主要介紹了IntelliJ IDEA使用教程從入門到上癮(2019圖文版),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
spring框架配置實(shí)體類復(fù)雜屬性注入xml文件過(guò)程詳解
這篇文章主要介紹了spring框架配置實(shí)體類復(fù)雜屬性注入xml文件過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09
Java反射之靜態(tài)加載和動(dòng)態(tài)加載的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇Java反射之靜態(tài)加載和動(dòng)態(tài)加載的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10
如何解決mybatisplus報(bào)錯(cuò):getSqlFirst問(wèn)題
這篇文章主要介紹了如何解決mybatisplus報(bào)錯(cuò):getSqlFirst問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-05-05
關(guān)于springboot中nacos動(dòng)態(tài)路由的配置
這篇文章主要介紹了springboot中nacos動(dòng)態(tài)路由的配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Java并發(fā)編程必備之Synchronized關(guān)鍵字深入解析
本文我們深入探索了Java中的Synchronized關(guān)鍵字,包括其互斥性和可重入性的特性,文章詳細(xì)介紹了Synchronized的三種使用方式:修飾代碼塊、修飾普通方法和修飾靜態(tài)方法,感興趣的朋友一起看看吧2025-04-04
springsecurity輕松實(shí)現(xiàn)角色權(quán)限的示例代碼
這篇文章主要介紹了springsecurity輕松實(shí)現(xiàn)角色權(quán)限的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Java 實(shí)戰(zhàn)項(xiàng)目之在線點(diǎn)餐系統(tǒng)的實(shí)現(xiàn)流程
讀萬(wàn)卷書不如行萬(wàn)里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+jsp+mysql+maven實(shí)現(xiàn)在線點(diǎn)餐系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平2021-11-11
java警告:源發(fā)行版17 需要目標(biāo)發(fā)行版17問(wèn)題及解決
文章介紹了如何解決項(xiàng)目JDK版本不一致的問(wèn)題,包括修改Project Structure、Modules、Dependencies和Settings中的JDK版本,以及在pom.xml中指定JDK源版本2024-11-11

