淺析Spring工廠的反射和配置文件
反射和配置文件
學(xué)習(xí) Spring 的時候,雖然可以知道是通過反射和配置文件的方式來獲取 JavaBean 對象,但是一直沒有機(jī)會自己嘗試一次,探究以下內(nèi)部原理,雖然有人推薦閱讀源碼,但是可能還是感覺學(xué)的不好,一直沒有嘗試過。現(xiàn)在剛好學(xué)習(xí)設(shè)計模式剛好遇到了這部分的內(nèi)容了,感覺自己對這個有了一個較好的理解了。
設(shè)計模式中,為了滿足開閉原則,大都引入了抽象層,如工廠方法模式、抽象工廠模式等。客戶端針對抽象層編程,而在程序運行的時候再指定其子類,根據(jù)里氏代換原則和面向?qū)ο蟮亩鄳B(tài)性,子類對象再運行時將覆蓋父類對象。如果需要對系統(tǒng)進(jìn)行擴(kuò)展,只需要修改子類類名即可。在具體實現(xiàn)時,通過引入配置文件可以使得用戶再不修改客戶端任何代碼的前提下增加或替換子類,
其基本實現(xiàn)過程過程為:
- 客戶端針對抽象層編程,客戶端代碼中不能出現(xiàn)具體的類名,即客戶端不直接實例化對象。
- 引入純文本格式的配置文件,通常是 XML 文件,將具體類類名存儲在配置文件中。
- 通過 DOM(Document Object Model,文檔對象模型)、SAX(SimpleAPI for XML)等 XML 解析技術(shù)獲取存儲在配置文件中類名。
- 在客戶端代碼中通過反射機(jī)制根據(jù)類名創(chuàng)建對象,用反射所創(chuàng)建的對象代替父類對象的引用,程序運行時,將調(diào)用子類方法來實現(xiàn)業(yè)務(wù)功能。
- 如果需要擴(kuò)展功能,只需要添加一個新的子類繼承抽象父類,再修改配置文件,重新運行程序即可;如果需要替換功能,只需要另一個子類類名替換存儲再配置文件中的原有子類類名。無論是擴(kuò)展還是替換都無須修改既有類庫和客戶端源碼,完全符合開閉原則。
Talk is cheap, show me the code.
直接通過代碼來理解上面的內(nèi)容吧。
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean>com.reflect.Dog</bean> </beans>
測試實體類
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 + "]"; } }
對象工廠類(類似Spring工廠的簡單實現(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é)點 NodeList nodeList = doc.getElementsByTagName("bean"); Node node = nodeList.item(0).getFirstChild(); String name = node.getNodeValue(); //通過類名生成實例對象并將其返回 Class<?> clazz = Class.forName(name); return clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); return null; } } }
測試類
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()); } }
項目目錄結(jié)構(gòu)
注意這里需要使用 dom4j 的jar包,下載導(dǎo)入即可!
運行結(jié)果
現(xiàn)在需求變了,不想使用 Dog 類,而要使用 HuntDog 類,只要增加 HuntDog 類, 并繼承 Dog 類即可,項目源碼不需要改動,滿足開閉原則。
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>
修改后的運行結(jié)果
總結(jié)
這個例子使用反射和配置文件,寫了一個滿足開閉原則的代碼,這點和 Spring的對象工廠思想很像(Spring 的設(shè)計思想很優(yōu)美,很龐大,這里只是我個人的理解),對于初學(xué) Spring的人應(yīng)該有一定的幫助(比如說我,哈哈)。
好了,大體來說這個例子非常的簡單,但是已經(jīng)足夠了,我覺得如果能用簡單的例子講好一個復(fù)雜的東西也是很厲害的,我也是在慢慢學(xué)習(xí),希望可以繼續(xù)進(jìn)步,加油!
到此這篇關(guān)于淺析Spring工廠的反射和配置文件的文章就介紹到這了,更多相關(guān)Spring工廠反射配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入理解Spring MVC的數(shù)據(jù)轉(zhuǎn)換
這篇文章主要給大家介紹了關(guān)于Spring MVC數(shù)據(jù)轉(zhuǎn)換的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧。2017-09-09SpringBoot使用攔截器Interceptor實現(xiàn)統(tǒng)一角色權(quán)限校驗
角色權(quán)限校驗,是保證接口安全必備的能力:有權(quán)限才可以操作,所以,一般對于這種通用邏輯,推薦不與主業(yè)務(wù)邏輯耦合,那么怎么來解耦,那么本文小編就給大家詳細(xì)講解如何使用攔截器Interceptor實現(xiàn)統(tǒng)一角色權(quán)限校驗,需要的朋友可以參考下2023-07-07解決spring中redistemplate不能用通配符keys查出相應(yīng)Key的問題
這篇文章主要介紹了解決spring中redistemplate不能用通配符keys查出相應(yīng)Key的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11詳解Spring Boot Admin監(jiān)控服務(wù)上下線郵件通知
本篇文章主要介紹了詳解Spring Boot Admin監(jiān)控服務(wù)上下線郵件通知,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12