淺析Spring工廠的反射和配置文件
反射和配置文件
學(xué)習(xí) Spring 的時(shí)候,雖然可以知道是通過(guò)反射和配置文件的方式來(lái)獲取 JavaBean 對(duì)象,但是一直沒(méi)有機(jī)會(huì)自己嘗試一次,探究以下內(nèi)部原理,雖然有人推薦閱讀源碼,但是可能還是感覺(jué)學(xué)的不好,一直沒(méi)有嘗試過(guò)。現(xiàn)在剛好學(xué)習(xí)設(shè)計(jì)模式剛好遇到了這部分的內(nèi)容了,感覺(jué)自己對(duì)這個(gè)有了一個(gè)較好的理解了。
設(shè)計(jì)模式中,為了滿足開(kāi)閉原則,大都引入了抽象層,如工廠方法模式、抽象工廠模式等。客戶端針對(duì)抽象層編程,而在程序運(yùn)行的時(shí)候再指定其子類,根據(jù)里氏代換原則和面向?qū)ο蟮亩鄳B(tài)性,子類對(duì)象再運(yùn)行時(shí)將覆蓋父類對(duì)象。如果需要對(duì)系統(tǒng)進(jìn)行擴(kuò)展,只需要修改子類類名即可。在具體實(shí)現(xiàn)時(shí),通過(guò)引入配置文件可以使得用戶再不修改客戶端任何代碼的前提下增加或替換子類,
其基本實(shí)現(xiàn)過(guò)程過(guò)程為:
- 客戶端針對(duì)抽象層編程,客戶端代碼中不能出現(xiàn)具體的類名,即客戶端不直接實(shí)例化對(duì)象。
- 引入純文本格式的配置文件,通常是 XML 文件,將具體類類名存儲(chǔ)在配置文件中。
- 通過(guò) DOM(Document Object Model,文檔對(duì)象模型)、SAX(SimpleAPI for XML)等 XML 解析技術(shù)獲取存儲(chǔ)在配置文件中類名。
- 在客戶端代碼中通過(guò)反射機(jī)制根據(jù)類名創(chuàng)建對(duì)象,用反射所創(chuàng)建的對(duì)象代替父類對(duì)象的引用,程序運(yùn)行時(shí),將調(diào)用子類方法來(lái)實(shí)現(xiàn)業(yè)務(wù)功能。
- 如果需要擴(kuò)展功能,只需要添加一個(gè)新的子類繼承抽象父類,再修改配置文件,重新運(yùn)行程序即可;如果需要替換功能,只需要另一個(gè)子類類名替換存儲(chǔ)再配置文件中的原有子類類名。無(wú)論是擴(kuò)展還是替換都無(wú)須修改既有類庫(kù)和客戶端源碼,完全符合開(kāi)閉原則。
Talk is cheap, show me the code.
直接通過(guò)代碼來(lái)理解上面的內(nèi)容吧。
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean>com.reflect.Dog</bean> </beans>
測(cè)試實(shí)體類
package com.reflect;
public class Dog {
private String name;
private Integer age;
public Dog() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Dog [name=" + name + ", age=" + age + "]";
}
}
對(duì)象工廠類(類似Spring工廠的簡(jiǎn)單實(shí)現(xiàn))
package com.reflect;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.*;
public class Factory {
public static Object getBean() {
try {
Document doc = DocumentBuilderFactory
.newInstance()
.newDocumentBuilder()
.parse("src/beans.xml");
//獲取包含類名的文本節(jié)點(diǎn)
NodeList nodeList = doc.getElementsByTagName("bean");
Node node = nodeList.item(0).getFirstChild();
String name = node.getNodeValue();
//通過(guò)類名生成實(shí)例對(duì)象并將其返回
Class<?> clazz = Class.forName(name);
return clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
測(cè)試類
package com.reflect;
public class Test {
public static void main(String[] args) {
Dog dog = null;
dog = (Dog)Factory.getBean();
dog.setName("小黑");
dog.setAge(12);
System.out.println(dog.toString());
}
}
項(xiàng)目目錄結(jié)構(gòu)
注意這里需要使用 dom4j 的jar包,下載導(dǎo)入即可!

運(yùn)行結(jié)果

現(xiàn)在需求變了,不想使用 Dog 類,而要使用 HuntDog 類,只要增加 HuntDog 類, 并繼承 Dog 類即可,項(xiàng)目源碼不需要改動(dòng),滿足開(kāi)閉原則。
package com.reflect;
public class HuntDog extends Dog {
private String name;
private Integer age;
public HuntDog() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "HuntDog [name=" + name + ", age=" + age + "]";
}
public void say() {
System.out.println("Hello, I am HuntDog: "+this.toString());
}
}
修改 XML 如下:
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean>com.reflect.HuntDog</bean> </beans>
修改后的運(yùn)行結(jié)果

總結(jié)
這個(gè)例子使用反射和配置文件,寫了一個(gè)滿足開(kāi)閉原則的代碼,這點(diǎn)和 Spring的對(duì)象工廠思想很像(Spring 的設(shè)計(jì)思想很優(yōu)美,很龐大,這里只是我個(gè)人的理解),對(duì)于初學(xué) Spring的人應(yīng)該有一定的幫助(比如說(shuō)我,哈哈)。
好了,大體來(lái)說(shuō)這個(gè)例子非常的簡(jiǎn)單,但是已經(jīng)足夠了,我覺(jué)得如果能用簡(jiǎn)單的例子講好一個(gè)復(fù)雜的東西也是很厲害的,我也是在慢慢學(xué)習(xí),希望可以繼續(xù)進(jìn)步,加油!
到此這篇關(guān)于淺析Spring工廠的反射和配置文件的文章就介紹到這了,更多相關(guān)Spring工廠反射配置內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(30)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你2021-07-07
JAVA中 Spring定時(shí)器的兩種實(shí)現(xiàn)方式
本文向您介紹Spring定時(shí)器的兩種實(shí)現(xiàn)方式,包括Java Timer定時(shí)和Quartz定時(shí)器,兩種Spring定時(shí)器的實(shí)現(xiàn)方式各有優(yōu)點(diǎn),可結(jié)合具體項(xiàng)目考慮是否采用。2015-09-09
Java中的static關(guān)鍵字修飾屬性和方法(推薦)
這篇文章主要介紹了Java中的static關(guān)鍵字修飾屬性和方法,包括哪些成員屬性可以被static修飾,靜態(tài)屬性的訪問(wèn)方法示例詳解,需要的朋友可以參考下2022-04-04
Java中RabbitMQ的幾種消息確認(rèn)機(jī)制
RabbitMQ消息確認(rèn)機(jī)制指的是在消息傳遞過(guò)程中,發(fā)送方發(fā)送消息后,接收方需要對(duì)消息進(jìn)行確認(rèn),以確保消息被正確地接收和處理,本文主要介紹了Java中RabbitMQ的幾種消息確認(rèn)機(jī)制,具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12

