Spring工廠方法創(chuàng)建(實(shí)例化)bean實(shí)例代碼
目標(biāo)明確
簡單敘述一下本文想要解決的問題:如何在Spring中不再使用Spring創(chuàng)建Bean實(shí)例,而是把Bean創(chuàng)建過程轉(zhuǎn)移到開發(fā)者手中。
思路清晰
創(chuàng)建Bean實(shí)例的方式:
1) 通過構(gòu)造器(有參或無參)
方式: <bean id="" class=""/>
2) 通過靜態(tài)工廠方法
方式: <bean id="" class="工廠類" factory-method="靜態(tài)工廠方法"/>
注: 工廠類實(shí)例沒有創(chuàng)建
3) 通過實(shí)例工廠方法(非靜態(tài)方法)
方式:
<bean id="factory" class="工廠類"/>
<bean id="" factory-bean="factory" factory-method="實(shí)例工廠方法"/>
注: 工廠類實(shí)例被創(chuàng)建
方法實(shí)用
示例1:
需求:
1 不想再bean.xml加載的時(shí)候?qū)嵗痓ean,而是想把加載bean.xml與實(shí)例化對象分離。
2 實(shí)現(xiàn)單例的bean
以上的情況,都可以通過工廠方法factory-method來創(chuàng)建bean。
這樣再加載bean.xml時(shí),不會(huì)直接實(shí)例化bean,而是當(dāng)調(diào)用factory-method所指的方法時(shí),才開始真正的實(shí)例化。
實(shí)現(xiàn):通過spring的factory-method來創(chuàng)建單例的bean
首先通過靜態(tài)內(nèi)部類創(chuàng)建一個(gè)單例對象
package com.spring.test.factorymethod;
public class Stage {
public void perform(){
System.out.println("演出開始...");
}
private Stage(){
}
private static class StageSingletonHolder{
static Stage instance = new Stage();
}
public static Stage getInstance(){
return StageSingletonHolder.instance;
}
}
在spring配置文件中指定加載的方法getInstance
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="theStage" class="com.spring.test.factorymethod.Stage"
factory-method="getInstance"></bean>
</beans>
通過應(yīng)用上下文調(diào)用bean獲取實(shí)例
package com.spring.test.factorymethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
Stage stage = ((Stage)ctx.getBean("theStage"));//.getInstance();
stage.perform();
}
}
執(zhí)行結(jié)果
一月 24, 2015 6:38:18 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@512dbd1a: startup date [Sat Jan 24 18:38:18 CST 2015]; root of context hierarchy 一月 24, 2015 6:38:19 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [bean.xml] 一月 24, 2015 6:38:19 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2d1879ea: defining beans [duke,sonnet29,poeticDuke,theStage]; root of factory hierarchy 演出開始...
工廠方法創(chuàng)建bean介紹
1. 使用靜態(tài)工廠方法創(chuàng)建Bean
使用靜態(tài)工廠方法創(chuàng)建Bean實(shí)例時(shí),class屬性也必須指定,但此時(shí)class屬性并不是指定Bean實(shí)例的實(shí)現(xiàn)類,而是靜態(tài)工廠類。因?yàn)镾pring需要知道是用哪個(gè)工廠來創(chuàng)建Bean實(shí)例。另外,還需要使用factory-method來指定靜態(tài)工廠方法名,Spring將調(diào)用靜態(tài)工廠方法(可能包含一組參數(shù)),來返回一個(gè)Bean實(shí)例,一旦獲得了指定Bean實(shí)例,Spring后面的處理步驟與采用普通方法創(chuàng)建Bean實(shí)例則完全一樣。需要注意的是,當(dāng)使用靜態(tài)工廠方法來創(chuàng)建Bean時(shí),這個(gè)factory-method必須要是靜態(tài)的。這段闡述聽上去有點(diǎn)暈,話不多說,上代碼:
先定義一個(gè)接口,靜態(tài)方法產(chǎn)生的將是該接口的實(shí)例:
public interface Animal {
public void sayHello();
}
下面是接口的兩個(gè)實(shí)現(xiàn)類:
public class Cat implements Animal {
private String msg;
//依賴注入時(shí)必須的setter方法
public void setMsg(String msg){
this.msg = msg;
}
@Override
public void sayHello(){
System.out.println(msg + ",喵~喵~");
}
}
public class Dog implements Animal {
private String msg;
//依賴注入時(shí)必須的setter方法
public void setMsg(String msg){
this.msg = msg;
}
@Override
public void sayHello(){
System.out.println(msg + ",旺~旺~");
}
}
下面的AnimalFactory工廠中包含了一個(gè)getAnimal的靜態(tài)方法,該方法將根據(jù)傳入的參數(shù)決定創(chuàng)建哪個(gè)對象。這是典型的靜態(tài)工廠設(shè)計(jì)模式。
public clas AnimalFactory {
public static Animal getAnimal(String type){
if ("cat".equalsIgnoreCase(type)){
return new Cat();
} else {
return new Dog();
}
}
}
如果需要指定Spring使用AnimalFactory來產(chǎn)生Animal對象,則可在Spring配置文件中作如下配置:
<!-- 配置AnimalFactory的getAnimal方法,使之產(chǎn)生Cat --> <bean id="cat" class="com.abc.AnimalFactory" factory-method="getAnimal"> <!-- 配置靜態(tài)工廠方法的參數(shù),getAnimal方法將產(chǎn)生Cat類型的對象 --> <constructor-arg value="cat" /> <!-- 通過setter注入的普通屬性 --> <property name="msg" value="貓貓" /> </bean> <!-- 配置AnimalFactory的getAnimal方法,使之產(chǎn)生Dog --> <bean id="dog" class="com.abc.AnimalFactory" factory-method="getAnimal"> <!-- 配置靜態(tài)工廠方法的參數(shù),getAnimal方法將產(chǎn)生Dog類型的對象 --> <constructor-arg value="dog" /> <!-- 通過setter注入的普通屬性 --> <property name="msg" value="狗狗" /> </bean>
從上面的配置可以看出:cat和dog兩個(gè)Bean配置的class和factory-method完全相同,這是因?yàn)閮蓚€(gè)實(shí)例都使用同一個(gè)靜態(tài)工廠類、同一個(gè)靜態(tài)工廠方法產(chǎn)生得到的。只是為這個(gè)靜態(tài)工廠方法指定的參數(shù)不同,使用<constructor-arg />元素來為靜態(tài)工廠方法指定參數(shù)。
主程序獲取cat和dog兩個(gè)Bean實(shí)例的方法不變,同樣只需要調(diào)用Spring容器的getBean()即可:
public class Test {
public static void main(String args[]){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Animal a1 = context.getBean("cat", Animal.class);
a1.sayHello();
Animal a2 = context.getBean("dog", Animal.class);
a2.sayHello();
}
}
輸出結(jié)果:
<code class="hljs">貓貓,喵~喵~ 狗狗,旺~旺~</code>
使用靜態(tài)工廠方法創(chuàng)建實(shí)例時(shí)必須提供工廠類和產(chǎn)生實(shí)例的靜態(tài)工廠方法。通過靜態(tài)工廠方法創(chuàng)建實(shí)例時(shí)需要對Spring配置文件做如下改變;
class屬性不在是Bean實(shí)例的實(shí)現(xiàn)類,而是生成Bean實(shí)例的靜態(tài)工廠類
使用factory-method指定生產(chǎn)Bean實(shí)例的靜態(tài)工廠方法
如果靜態(tài)工廠方法需要參數(shù),使用<constructor-arg />元素為其配置
當(dāng)我們指定Spring使用靜態(tài)工廠方法來創(chuàng)建Bean實(shí)例時(shí),Spring將先解析配置文件,并根據(jù)配置文件指定的信息,通過反射調(diào)用靜態(tài)工廠類的靜態(tài)工廠方法,并將該靜態(tài)工廠方法的返回值作為Bean實(shí)例,在這個(gè)過程中,Spring不再負(fù)責(zé)創(chuàng)建Bean實(shí)例,Bean實(shí)例是由用戶提供的靜態(tài)工廠方法提供的。
2. 使用實(shí)例工廠方法創(chuàng)建Bean
實(shí)例工廠方法與靜態(tài)工廠方法只有一點(diǎn)不同:調(diào)用靜態(tài)工廠方法只需要使用工廠類即可,調(diào)用實(shí)例工廠方法則必須使用工廠實(shí)例。所以在Spring配置上也只有一點(diǎn)區(qū)別:配置靜態(tài)工廠方法指定靜態(tài)工廠類,配置實(shí)例工廠方法則指定工廠實(shí)例。同樣是上面的例子將AnimalFactory修改為:
public clas AnimalFactory {
public Animal getAnimal(String type){ //這里僅僅是去掉了static關(guān)鍵字
if ("cat".equalsIgnoreCase(type)){
return new Cat();
} else {
return new Dog();
}
}
}
Spring文件修改為:
<!-- 先配置工廠類 --> <bean id="animalFactory" class="com.abc.AnimalFactory" /> <!-- 這里使用factory-bean指定實(shí)例工廠類對象 --> <bean id="cat" factory-bean="animalFactory" factory-method="getAnimal"> <!-- 同樣指定factory-method的參數(shù) --> <constructor-arg value="cat" /> <property name="msg" value="貓貓" /> </bean> <bean id="dog" factory-bean="animalFactory" factory-method="getAnimal"> <constructor-arg value="dog" /> <property name="msg" value="狗狗" /> </bean>
測試類不用修改,輸出結(jié)果和上面相同。
很多情況下使用<bean id=”bean1” class=”…” />定義一個(gè)bean,這種定義方式Spring將會(huì)調(diào)用默認(rèn)的無參數(shù)構(gòu)造方法創(chuàng)建Bean實(shí)例。除此之外還可以使用工廠方式創(chuàng)建Bean實(shí)例,實(shí)現(xiàn)Bean創(chuàng)建與使用的分離,將Bean創(chuàng)建工作交由工廠來完成。
配置工廠Bean的三種方式。
抽象接口:
public interface IMusicBox {
public void play();
}
1、靜態(tài)工廠方法取得Bean實(shí)例
工廠類:
public class MusicBoxFactory {
public static IMusicBox createMusicBox(){
return new IMusicBox(){
public void play(){
System.out.println("Play piano...");
}
};
}
}
配置文件:
<bean id="musicBox" class="test.spring.MusicBoxFactory" factory-method="createMusicBox" />
測試類:
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("bean-config.xml");
IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox");
musicbox.play();
}
2、工廠實(shí)例的方法取得Bean實(shí)例
工廠類:
public class MusicBoxFactory {
public IMusicBox createMusicBox(){//沒有static修飾
return new IMusicBox(){
public void play(){
System.out.println("Play piano...");
}
};
}
}
配置文件:
<bean id="factoryBean" class="test.spring.MusicBoxFactory" /> <bean id="musicBox" factory-bean="factoryBean" factory-method="createMusicBox" />
“factory-bean”屬性指定工廠Bean,”factory-method”屬性指定工廠方法來取得Bean實(shí)例。
測試類:
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("bean-config.xml");
IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox");
musicbox.play();
}
3、工廠類實(shí)現(xiàn)org.springframework.beans.factory.FacotryBean接口
工廠類:
import org.springframework.beans.factory.FactoryBean;
public class MusicBoxFactory2 implements FactoryBean {
public Object getObject() throws Exception {
return new IMusicBox(){
public void play(){
System.out.println("Play piano...");
}
};
}
public Class getObjectType() {
return IMusicBox.class;
}
public boolean isSingleton() {
return false;
}
}
配置文件:
<bean id="musicBox" class="test.spring.MusicBoxFactory2"/>
測試類:
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("bean-config.xml");
//不加 & 返回工廠的“產(chǎn)品”
IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox");
musicbox.play();
//加 & 返回工廠類實(shí)例
Object obj = ctx.getBean("&musicBox");
System.out.println(obj.getClass().getName());
}
實(shí)現(xiàn)FactoryBean接口的類不會(huì)被視為普通的Bean,Spring會(huì)自動(dòng)檢測,調(diào)用getObject方法獲取Bean實(shí)例
總結(jié)
Spring工廠方法實(shí)例化bean實(shí)例的介紹就到這里,有什么不足之處,大家可以留言指出。感謝朋友們對本站的支持!
相關(guān)文章
spring?參數(shù)校驗(yàn)Validation示例詳解
Spring提供了Validation工具類來實(shí)現(xiàn)對客戶端傳來的請求參數(shù)的有效校驗(yàn),本文給大家介紹spring?參數(shù)校驗(yàn)Validation示例詳解,感興趣的朋友一起看看吧2024-12-12
Spring?AI借助全局參數(shù)實(shí)現(xiàn)智能數(shù)據(jù)庫操作與個(gè)性化待辦管理
這篇文章主要介紹了Spring?AI借助全局參數(shù)實(shí)現(xiàn)智能數(shù)據(jù)庫操作與個(gè)性化待辦管理,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-11-11
Java Map 按照Value排序的實(shí)現(xiàn)方法
Map是鍵值對的集合接口,它的實(shí)現(xiàn)類主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。這篇文章主要介紹了Java Map 按照Value排序的實(shí)現(xiàn)方法,需要的朋友可以參考下2016-08-08
IntelliJ IDEA 安裝教程2019.09.23(最新版)
本文通過圖文并茂的形式給大家介紹了IntelliJ IDEA 安裝教程2019.09.23最新版,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10
深入了解Spring Boot2.3.0及以上版本的Liveness和Readiness功能
這篇文章主要介紹了Spring Boot2.3.0及以上版本的Liveness和Readiness功能示例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
java poi實(shí)現(xiàn)Excel多級表頭導(dǎo)出方式(多級表頭,復(fù)雜表頭)
文章介紹了使用javapoi庫實(shí)現(xiàn)Excel多級表頭導(dǎo)出的方法,通過主代碼、合并單元格、設(shè)置表頭單元格寬度、填充數(shù)據(jù)、web下載和提供表頭樣式、內(nèi)容樣式以及標(biāo)題樣式等步驟,作者實(shí)現(xiàn)了最終的效果2025-01-01
Java中字節(jié)流和字符流的區(qū)別與聯(lián)系
Java中的字節(jié)流和字符流是用于處理輸入和輸出的兩種不同的流,本文主要介紹了Java中字節(jié)流和字符流的區(qū)別與聯(lián)系,字節(jié)流以字節(jié)為單位進(jìn)行讀寫,適用于處理二進(jìn)制數(shù)據(jù),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2024-12-12
mybatis整合spring實(shí)現(xiàn)開啟mapper.xml映射文件掃描
這篇文章主要介紹了mybatis整合spring實(shí)現(xiàn)開啟mapper.xml映射文件掃描,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10

