天天看點

淺析Spring IOC(控制反轉)

一、BeanFactory輕量級

三種通路ApplicationContext.xml方式:

1、Resource resource = new ClassPathResource(“application.xml”);

BeanFactory factory = new XmlBeanFactory(resource);

HelloWorld hello = factory.getBean(“fileHelloWorld”);

2、基于檔案找到application.xml

InputStream is = new FileInputStream(“src/application.xml”);

BeanFactory factory = new XmlBeanFactory(is);

3、基于ApplicationContext

ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[]{“application.xml”});

BeanFactory factory = (BeanFactory)appContext;

Bean的生命周期

1、執行個體化JavaBean

2、JavaBean執行個體初始化,即通過IOC注入其依賴性。這一階段将完成JavaBean執行個體初始化

3、基于Spring應用對JavaBean執行個體的使用

4、IOC容器銷毀JavaBean執行個體

Bean的建立

<bean name="fileHelloWorld" class="com.jader.FileHelloWorld">
           

HelloWorld執行個體将使用無參數建構器建立出來

<bean name="fileHelloWorld" class="com.jader.FileHelloWorld" factory-method="createHelloWorldInstance">
           

HelloWorld必須提供createHelloWorldInstance的靜态方法

<bean name="helloWorldFactory" class="com.jader.FileHelloWorldFactory" />
<bean name="fileHelloWorld" class="com.jader.FileHelloWorld" factory-bean="helloWorldFactory' factory-method="createFileHelloWorldInstance">

           

此種情況類不需要提供靜态方法,命名為fileHelloWorld的JavaBean執行個體将通過helloWorldFactory工廠類的createFileHelloWorldInstance方法獲得

<bean name="fileHelloWorld" class="com.jader.FileHelloWorld">
    <constructor-arg>
        <ref bean="fileHello"/>
    </constructor>
</bean>
           

通過ref元素引用Spring配置檔案中的fileHello,ref有以下幾個屬性:

1、bean:在目前Spring XML配置檔案中,或者在同一個BeanFactory(applicationContext)中的其他JavaBean中

2、local:在目前Spring XML配置檔案中,其依賴的JavaBean必須存在于目前Spring XML配置檔案中,

3、parent:用于指定其依賴的父JavaBean定義

初始化JavaBean

1、如果開發者使用了元素的autowire屬性,Spring能夠自動将目标JavaBean需要注入的JavaBean找到并注入進來。

2、如果開發者指定了元素的dependency-check屬性,則能夠保證各個Spring配置檔案中各個JavaBean之間的互相關系。

3、借助于setter方法能夠将JavaBean的屬性值注入進來,這些屬性可以是Java原型(primitive)、對象類型,甚至可以是null

例如:

<bean id="helloWorld" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager">
        <ref local="transactionManager"/>
    </property>
    <property name="transactionAttributers">
        <props>
            <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="set*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>
           

Spring架構能夠注入TransactionProxyFactoryBean中的transactionManager、target、transactionAttributes所需的屬性值。比如:transactionManager屬性取值通過ref引用了transactionManager的POJO服務。如果Spring配置檔案中不存在事務管理器,開發者有兩種做法:

單獨定義新的transactionManager,例如:

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="userTransactionName">
        <value>java:comp/UserTransaction</value>
    </property>
</bean>
           

ref會引用transactionManager

定義内部JavaBean方法:

<propery name="transactionManager">
    <bean class="org.springframework.transaction.jat.JtaTransactionManager">
        <property name="userTransactionName">
            <value>java:comp/UserTransaction</value>
        </property>
    </bean>
</property>
           

通過定義内部JavaBean,其他JavaBean便不能夠引用到他,而且開發者再也不能夠重用JtaTransactionManager。現實場合存在這種需求,存在即是合理。

4、如果JavaBean實作了如下接口,還需要調用setBeanFactory方法

org.springframework.beans.factory.BeanFactoryAware

其定義了方法如下:

void setBeanFactory(BeanFactory beanFactory) throws BeansException;

5、Spring架構提供了若幹接口,供開發者改變配置再BeanFactory中JavaBean的行為适用,其中InitializingBean接口介紹如下:

org.springframework.beans.factory.InitializingBean在BeanFactory初始化JavaBean時,BeanFactory會調用那些實作了InitializingBean接口的JavaBean中包含的方法:

void afterPropertiesSet() throws Exception;// InitializingBean定義的方法

6、最後通過在元素中包含init-method屬性能夠達到同InitializingBean一樣的目的,即:

<bean name="fileHelloWorld" class="com.openv.spring.HelloWorld" init-method="init">
           

HelloWorld将實作init方法

通過以上6步,完成JavaBean執行個體的初始化工作

使用JavaBean

借助于getBean方法,開發者就能夠在應用中使用他了

銷毀JavaBean

一旦将基于Spring的應用停止,Spring架構将調用那些JavaBean執行個體中存在的生命周期方法,比如:DisposableBean接口的JavaBean或者那些在Spring配置檔案中指定了destory-method屬性的JavaBean。

最終Spring将銷毀JavaBean執行個體。

注意:這些内容隻适合于那些通過singleton方法建立的JavaBean執行個體,對于那些以prototype方式建立的JavaBean執行個體,Spring并不能夠控制器生命周期,因為這種JavaBean執行個體建立成功,整個JavaBean将傳遞給Spring應用去管理。

其中,DisposableBean介紹如下:

org.springframework.beans.factory.DisposableBean:在BeanFactory銷毀JavaBean時,BeanFactory會調用那些實作了DisposableBean接口的JavaBean中包含的如下方法:

void destory() throws Exception;

其中,destroy是DisposableBean定義的方法。

當然,通過在元素中包含destroy-method屬性能夠達到同DisposableBean一樣的目的,即:

如果應用同僚實作了兩種方法,Spring先執行DisposableBean中的的destroy方法。

抽象Bean和子Bean定義

将公共内容放置在抽象bean中,子Bean能夠重用抽象Bean中定義的内容,而且還能夠“重載”他們。

PropertyPlaceholderConfigurer和PropertyOverrideConfigurer

對于PropertyPlaceholderConfigurer而言,他能夠在Spring配置檔案外部配置其他應用使用到的屬性,比如:通過Java屬性檔案配置資料庫連接配接資訊、LDAP(目錄通路協定)、活動目錄連接配接資訊。

例如:Apache DBCP資料源執行個體:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName"
        <value>${jdbc.driverClassName}</value>
    </property>
    <property name="url">
        <value>${jdbc.url}</value>
    </property>
    <property name="username">
        <value>${jdbc.username}</value>
    </property>
    <property name="password">
        <value>${jdbc.password}</value>
    </property>
</bean>
其中$裡面的驅動名、url、使用者名、密碼的實際值通過Java屬性檔案獲得。
<bean id="propertyConfigurer" class="org.springframework.bean.factory.config.ProperryPlaceholderConfigurer">
    <property name="location">
        <value>jdbc.properties</value>
    </property>
</bean>
           

BeactoryAware與BeanNameAware

對于某些基于Spring的應用而言,有一些将應用的BeanFactory執行個體注入到JavaBean執行個體中。比如:為在某JavaBean執行個體中動态獲得BeanFactory建立的某單例JavaBean,但是該單例JavaBean并沒有顯式的使用它,此時借助于BeanFactoryAware能夠滿足開發者要求,例如:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName">
        <value>java:/MysqlDS</value>
    </property>
</bean>
<bean id="exampleServiceTarget" class="com.openv.spring.service.impl.ExampleManagerImpl">
    <property name="userInfo">
        <ref local="userInfoDao" />
    </property>
</bean>
           

如果在exampleServiceTarget中需要使用dataSource,但是在Spring配置檔案中并沒有顯式的配置對dataSource的引用。此時,需要借助于BeanFactoryAware,即ExampleManagerImpl需要實作BeanFactoryAware接口。

如果需要在JavaBean執行個體中獲悉其配置的名字,可以考慮實作BeanNameAware接口:

org.springframework.beans.factory.BeanNameAware

其定義了如下方法:

void setBeanName(String name);

其執行時間在調用InitializingBean afterPropertiesSet或者自定義init-method之前,而在JavaBean屬性正常指派之後。

二、ApplicationContext

Spring架構引入了ApplicationContext接口,開發者不需要手工建立ApplicationContext執行個體,便可以聲明的方式使用它。例如:

org.springframework.web.context.ContextLoaderServlet或者

org.springframework.web.context.ContextLoaderListener

能夠在web應用啟動的時候自動執行個體化ApplicationContext對象,對于SpringBeanFactory而言,如果使用者沒有調用getBean()方法,則使用到的JavaBean執行個體将會被建立。是以在BeanFactory中使用了延遲裝載的機制,這主要是同BeanFactory的應用場合有關。對于Spring ApplicationContext而言,一旦ContextLoaderServlet或ContextLoaderListener初始化成功所有的JavaBean執行個體将會被建立(除非開發者改變了ApplicationContext的預設行為,比如顯式的設定延遲裝載行為)

開發者應該注意到Log4jConfigServlet,供配置Spring應用的日志使用,使用方法同ContextLoaderServlet,如下:

<context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<servlet>
    <serlvet-name>log4jConfigServlet</servlet-name>
    <serlvet-class>
        org.springframework.web.util.Log4jConfigServlet
    </servlet-class>
    <load-on-startup></load-on-startup>
</servlet>
           

(>0表示容器在應用啟動時就加載并初始化這個servlet,

當值小于0或者沒有指定時,則表示容器在該servlet被選擇時才會去加載,

正數的值越小,該servlet的優先級越高,應用啟動時就越先加載)

淺析Spring IOC(控制反轉)

開發者應該注意到Log4jConfigListener類供配置Spring應用的日志使用,由于ApplicationContext含有BeanFactory的所有功能,是以對于開發J2EE應用場合推薦使用ApplicationContext。

1、Web應用中建立ApplicationContext

Web應用自動過程中将自動初始化監聽器,而ContextLoaderListener就是監聽器,例如:

<context-param>
    <param-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
           

2、ApplicationContextAware

在為某JavaBean執行個體動态獲得ApplicationContext建立的某單例JavaBean,但是該單例JavaBean并沒有顯式的使用(在Spring配置檔案沒有顯式的給出對單例JavaBean的引用,例如未使用元素),借助于ApplicationContextAware能夠滿足開發者的要求

介紹如下:

org.springframework.context.ApplicationContextAware

其定義了如下方法:

void setApplicationContext(ApplicationContext applicationContext);

現有如下示例代碼:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" >
    <property name="jndiName">
        <value> java:/MySqlDS</value>
    </property>
</bean>
<bean id="exampleServiceTarget" class="com.openv.spring.service.impl.ExampleManagerImpl">
    <property name="userInfo">
        <ref local="userInfoDao" />
    </property> 
</bean>
           

如果在exampleServiceTarget需要使用到dataSource,但是Spring配置檔案中沒有顯式的配置對dataSource的引用,此時可以借助ApplicationContextAware接口。

示例代碼:

public class ExampleManagerImpl implements ApplicationContextAware{
    private ApplciationContext applicationContext;
    public void setApplicationContext(ApplicationContext applicationContext){
        this.applicationContext = applicationContext;
    }

    pubic DataSource getDataSource(){
        DataSource ds = null;
        ds = (DataSource)applicationContext.getBean("dataSource");
        retrun ds;
    }
}
           

這同BeanFactoryAware類似。

3、ApplicationContext接口實作

ClassPathXmlApplicationContext:在Web應用中,開發者可以從其classpath中,即WEB-INF/classes或WEB-INF/lib的jar中裝載Spring配置檔案

FileSystemXMLApplicationContext:開發者可以從檔案系統中裝載Spring配置檔案

XMLWebApplicationContext:供ContextLoaderListener或ContextLoaderServlet内部裝載Spring配置檔案使用。