Spring IOC

什麼是控制反轉
什麼是依賴注入
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"));

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章