什麼是控制反轉
什麼是依賴注入
BeanFactory
ApplicationContext
Bean的scope
Bean的生命週期
Type2 Ioc、Type3 IoC
集合對象
資源、消息、事件
什麼是控制反轉?
IoC,用白話來講,就是由容器控制程序之間的關係,而非傳統實現中,由程序代碼直接操控。這也就是所謂“控制反轉”的概念所在:控制權由應用代碼中轉到了外部容器,控制權的轉移,是所謂的反轉。
什麼是依賴注入?
相對IoC 而言,“依賴注入”的確更加準確的描述了這種設計理念。從名字上理解,所謂依賴注入,即組件之間的依賴關係由容器在運行期決定,形象的來說,即由容器動態的將某種依賴關係注入到組件之中。
依賴注入的幾種實現類型
Type1 IoC(接口注入)
Type2 IoC(設值注入)
Type3 IoC(構造注入)
BeanFactory
BeanFactory負責讀取Bean定義文件;管理對象的加載、生成;維護Bean對象與Bean對象之間的依賴關係;負責Bean的生命週期。BeanFactory接口包括了5種方法可以調用:
boolean containsBean(String name)
是否包含指定名稱的Bean
Object getBean(String name)
取得相對應的Bean實例
Object getBean(String name,Class requiredType)
取得相對應的Bean實例,並轉換到指定的類
Class getType(String name)
取得相對應的Bean的Class實例
boolean isSingleton(String name)
測試指定的Bean之scope是否爲Singleton
ApplicationContext
ApplicationContext提供一個應用程序所需的更完整的框架功能,例如:
提供更方便地取得資源文件的方法
提供解析文字消息的方法
支持國際化消息
可以發佈事件,對事件感興趣的Bean可以接收這些事件
在實現ApplicationContext的類中,最常使用的是以下3個:
FileSystemXmlApplicationContext
可指定XML定義文件的相對路徑或絕對路徑讀取定義文件
ClassPathXmlApplicationContext
從Classpath設置路徑中讀取XML定義文件
XmlWebApplicationContext
在Web應用程序的文件架構中,指定相對位置讀取定義文件
舉例:
可以將第一個Spring程序中的SpringDemo類修改爲以下內容:
package org.fire;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringDemo {
public static void main(String[] args) {
ApplicationContext context=new
ClassPathXmlApplicationContext("beans-config.xml");
HelloBean hello=(HelloBean) context.getBean("helloBean");
System.out.println(hello.getHelloWorld());
}
}
Bean的scope
在Spring中,從BeanFactory或ApplicationContext取得的實例被默認爲Singleton,也就是默認每一個Bean名稱只維持一個實例。
使用Singleton模式產生單一實例,對單線程的程序來說不會有什麼問題,但對於多線程的程序,必須注意到線程安全的問題,防止多個線程同時存取共用資源所引發的數據不同步問題,通常Singleton的Bean都是無狀態的。
在Spring中,“scope”屬性預設是“singleton”,通過將其設置爲“prototype”,使得每次指定名稱來取得Bean時,都會產生一個新的實例。
舉例:
<bean id="date" class="java.util.Date" scope="singleton" />
Resource rs = new ClassPathResource("beans-config1.xml");
BeanFactory factory = new XmlBeanFactory(rs);
Date d1 = (Date) factory.getBean("date");
Thread.sleep(1000);
Date d2 = (Date) factory.getBean("date");
System.out.println(d1);
System.out.println(d2);
<bean id="date" class="java.util.Date" scope="prototype" />
Resource rs = new ClassPathResource("beans-config2.xml");
BeanFactory factory = new XmlBeanFactory(rs);
Date d1 = (Date) factory.getBean("date");
Thread.sleep(1000);
Date d2 = (Date) factory.getBean("date");
System.out.println(d1);
System.out.println(d2);
Bean的生命週期
一個Bean從建立到銷燬,會歷經幾個執行階段,我們可以在Bean的配置文件中定義“init-method”屬性來設置初始化方法;定義“destroy-method”屬性來設置銷燬方法。
<bean id="beanLife“
class="BeanLife"
lazy-init="true"
init-method="init"
destroy-method="destroy">
</bean>
public class BeanLife {
public void init(){
System.out.println("init");
}
public void destroy(){
System.out.println("destroy");
}
public static void main(String[] args) {
AbstractApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
BeanLife life=(BeanLife) context.getBean("beanLife");
//向JVM註冊關閉
context.registerShutdownHook();
}
}
Type2 Ioc、Type3 IoC
在Spring中兩種基本的依賴注入方式是設值注入及構造注入。在第1章完成的第一個Spring程序中,利用了Bean的Setter方法完成依賴注入。下面來介紹構造注入如何實現。
實現步驟:
JavaBean
import java.util.Date;
public class HelloBean {
private String helloWorld;
private Date date;
public HelloBean(String helloWorld, Date date) {
this.helloWorld = helloWorld;
this.date = date;
}
……
}
Bean的配置文件
<bean id="date" class="java.util.Date" />
<bean id="helloBean" class="HelloBean">
<constructor-arg index="0">
<value>Hello,fire</value>
</constructor-arg>
<constructor-arg index="1">
<ref bean="date" />
</constructor-arg>
</bean>
示範程序
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringDemo {
public static void main(String[] args) {
ApplicationContext context=new
ClassPathXmlApplicationContext("applicationContext.xml");
HelloBean hello=(HelloBean) context.getBean("helloBean");
System.out.println(hello.getHelloWorld());
System.out.println(hello.getDate());
}
}
集合對象
對於Array、List 、Set 、Map等集合對象,在注入前必須填充入一些對象至集合中,然後再將集合注入至所需的Bean,也可以交由Spring的IoC容器來自動維護或生成集合對象,並完成依賴注入。
實現步驟:
JavaBean
import java.util.List;
import java.util.Map;
public class SomeBean {
private String[] someArray;
private List someList;
private Map someMap;
……
}
Bean的配置文件
<bean id="someBean" class="SomeBean">
<property name="someArray">
<list>
<value>1</value><value>2</value><value>3</value>
</list>
</property>
<property name="someList">
<list>
<value>張三</value><value>李四</value><value>五王</value>
</list>
</property>
<property name="someMap">
<map>
<entry key="1"><value>路人甲</value></entry>
<entry key="2"><value>路人乙</value></entry>
</map>
</property>
</bean>
示範程序
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
SomeBean some = (SomeBean) context.getBean("someBean");
// 取得Array類型依賴注入對象
String[] strs = some.getSomeArray();
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
// 取得List類型依賴注入對象
List list=some.getSomeList();
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 取得Map類型依賴注入對象
Map map=some.getSomeMap();
System.out.println(map.get("1"));
System.out.println(map.get("2"));
資源、消息、事件
資源的取得
ApplicationContext.getResource()方法提供了對資源文件訪問的支持,示例如下:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲得資源對象
Resource rs = context.getResource("classpath:test.txt");
// Resource rs = context.getResource("file:src/test.txt");
//資源文件是否存在
if (rs.exists()) {
//輸出資源文件的絕對路徑
System.out.println(rs.getFile().getAbsolutePath());
//獲得資源文件的輸入流對象
InputStream in=rs.getInputStream();
InputStreamReader inr=new InputStreamReader(in);
while(inr.ready()){
System.out.print((char)inr.read());
}
in.close();inr.close();
}
解析文字消息
ApplicationContext繼承了MessageSource接口,可以使用getMessage()的各種版本的方法來取得文字消息的資源文件,從而實現國際化消息的目的。
messages_en.properties
User {0} login at {1}
messages_zh.properties
用戶 {0} 於 {1} 登錄
<!-- 使用ResourceBundleMessageSource來取國際化消息 -->
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<!-- 設置消息資源的前置檔案文件名稱 -->
<property name="basename" value="messages"></property>
</bean>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 消息中需要傳遞的參數
Object[] arg = { "Fire", new Date() };
// 輸出英文消息
System.out.println(context.getMessage("userLogin", arg, Locale.US));
// 輸出中文消息
System.out.println(context.getMessage("userLogin", arg, Locale.CHINA));
事件傳播
如果打算髮布事件通知ApplicationListener的實例,可以使用ApplicationContext的publishEvent()方法。示例如下:
//自定義動作事件
public class ActionEvent extends ApplicationEvent {
public ActionEvent(Object source) {
super(source);
}
}
<bean id="listener" class="ActionListener" />
//自定義動作事件監聽器
public class ActionListener implements ApplicationListener{
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof ActionEvent){
System.out.println(event.getSource());
}
}
}
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
context.publishEvent(new ActionEvent("Hello"));
Spring IOC
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.