若是有這樣的需求:spring
1 不想再bean.xml加載的時候實例化bean,而是想把加載bean.xml與實例化對象分離。安全
2 實現單例的beanspa
以上的狀況,均可以經過工廠方法factory-method來建立bean。線程
這樣再加載bean.xml時,不會直接實例化bean,而是當調用factory-method所指的方法時,纔開始真正的實例化。code
首先看一下傳統的單例模式的實現方式:orm
public class SingletonOne { private static SingletonOne instance = null; private SingletonOne() {} public static SingletonOne getInstance() { if (instance == null) { instance = new SingletonOne(); } return instance; } }
可是這種方法有一個弊端,就是存在線程的不安全!xml
好比當兩個線程同時進入if(instance == null)時,一個線程判斷了當前爲空,而後切換到另外一個線程,這個線程也判斷爲空。而後切換回第一個線程,進行實例化,再切換到第二個線程,進行實例化。這樣就存在了兩個實例。對象
package com.something.singleton; public class SingletonTwo { private static SingletonTwo instance = null; private SingletonTwo() {} public static synchronized SingletonTwo getInstance() { if (instance == null) { instance = new SingletonTwo(); } return instance; } }
這樣當線程進行到getInstance會同步的進行,不會有線程安全問題,可是不單單是實例化,每次調用也須要同步,這樣就會形成不少資源的浪費。blog
public class SingletonThree { private static class SingletonHolder{ static SingletonThree instance = new SingletonThree(); }
private SingletonThree() {} public static SingletonThree getInstance() { return SingletonHolder.instance; } }
這種方法時最推薦的一種方法,因爲Java的調用機制,SingletonHolder只有在調用getInstance的時候纔會加載,而內部的靜態類只會被加載一次,所以又是線程安全的。資源
總結起來:
第一種方法,是存在線程安全問題的。
第二種方法,則消耗了必定的資源。
第三種方法,比較推薦。
首先經過靜態內部類建立一個單例對象
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>
經過應用上下文調用bean獲取實例
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(); } }
執行結果
一月 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 演出開始...