1. 程式人生 > >spring的基本用法

spring的基本用法

共享 url sin 事件 參數類型 有用 patch 2.4 init

1,關於spring容器: spring容器是Spring的核心,該 容器負責管理spring中的java組件,
ApplicationContext ctx  = new ClassPathXmlApplicationContext("bean.xml");//這種方式實例化容器,容器會自動預初始化所有Bean實例
ctx.getBean("beanName");
ApplicationContext 實例正是Spring容器。 ApplicationContext 容器默認會實例化所有的singleton Bean Spring容器並不強制要求被管理組件是標準的javabean。 2,Spring的核心機制:依賴註入。 不管是依賴註入(Dependency Injection)還是控制反轉(Inversion of Conctrol),其含義完全相同: 當某個java實例(調用者)需要調用另一個java實例(被調用者)時,傳統情況下,通過調用者來創建被調用者的實例,通常通過new來創建, 而在依賴註入的模式下創建被調用者的工作不再由調用者來完成,因此稱之為"控制反轉";創建被調用者實例的工作通常由Spring來完成,然後註入調用者,所以也稱之為"依賴註入"。 3,依賴註入一般有2中方式: 設置註入:IoC容器使用屬性的setter方式註入被依賴的實例。<property name="" ref=""> 構造註入:IoC容器使用構造器來註入被依賴的實例。<constructor-arg ref=""> 配置構造註入的時候<constructor-arg>可以配置index屬性,用於指定該構造參數值作為第幾個構造參數值。下表從0開始。 4,Spring容器和被管理的bean: Spring有兩個核心接口:BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口。他們都可以代表Spring容器。 Spring容器是生成Bean實例的工廠,並管理Spring中的bean,bean是Spring中的基本單位,在基於Spring的java EE工程,所有的組件都被當成bean處理。 包括數據源、Hibernate的SessionFactory、事務管理器。 ①Spring容器:Spring最基本的接口就是BeanFactory, BeanFactory有很多實現類,通常使用XmlBeanFactory,但是對於大部分的javaEE應用而言,推薦使用ApplictionContext,它是BeanFactory的子接口, ApplictionContext的實現類為FileSystemXmlApplicationContext和ClassPathXmlApplicationContext FileSystemXmlApplicationContext:基於文件系統的XML配置文件創建ApplicationContext; ClassPathXmlApplicationContext:基於類加載路徑下的xml配置文件創建ApplicationContext。 ②ApplicationContext的事件機制, ApplicationContext事件機制是基於觀察者設計模式實現的。通過ApplicationEvent類和ApplicationListener接口, 其中ApplicationEvent:容器事件,必須由ApplicationContext發布; ApplicationListener:監聽器,可有容器內的任何監聽器Bean擔任。 ③容器中bean的作用域: singleton:單例模式,在整個Spring IoC容器中,使用singleton定義的bean將只有一個實例; prototype:原型模式,每次通過容器的getBean方法獲取prototype定義的Bean時,都將產生一個新實例; request:對於每次HTTP請求中,使用request定義的bean都將產生一個新實例,只有在web應用程序使用Spring時,該作用域才有效; session:同理 global session:同理 註意:request和session作用域只在web應用中才生效,並且必須在web應用中增加額外的配置才會生效,為了讓request,session兩個作用域生效,必須將HTTP請求對象綁定到為該請求提供服務的線程上,這使得具有request和session作用域的Bean實例能夠在後面的調用鏈中被訪問。 當支持Servlet2.4及以上規範的web容器時,我們可以在web應用的web.xml增加如下Listener配置,該Listener負責為request作用域生效:
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
如果僅使用了支持Servlet2.4以前規範的web容器,則該容器不支持Listener規範,故無法使用這種配置,可以使用Filter配置方式,我們可以在web應用的web.xml增加如下Filter配置:
<filter>
    <filter-name>requestContextFilter</filter-name>
    <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
 <filter-mapping>
     <filter-name>requestContextFilter</filter-name>
      <url-pattern>/*</url-pattern>  
 </filter-mapping>
再如下面的代碼:
<bean id="p" class="lee.Person" scope="request"/>
這樣容器就會為每次HTTP請求生成一個lee.Person的實例當該請求響應結束時,該實例也隨之消失。 如果Web應用直接使用Spring MVC作為MVC框架,即使用SpringDispatchServlet或DispatchPortlet來攔截所有用戶請求,則無需這些額外的配置,因為SpringDispatchServlet或DispatchPortlet已經處理了所有和請求有關的狀態處理。 ④獲取容器的引用: 通常情況下: Bean無需訪問Spring容器,而是通過Spring容器訪問的,即使 需要手動訪問Spring容器,程序也已通過類似下面的代碼獲取Spring容器 的引用。 ApllicationContext cts = ClassPathApplalicationContext("bean.xml"); 但在一些極端的情況下,可能Bean需要訪問Spring容器。Spring提供另一種方法訪問Spring容器: 實現BeanFactoryAware接口的Bean,擁有訪問Spring容器的能力,實現BeanFactoryAware的Bean被容器實例化後,會擁有一個引用指向創建他的BeanFactory。BeanFactoryAware只有一個方法setBeanFactory(BeanFactory beanFactory)該參數指向創建他的BeanFactory。 缺點:汙染了代碼,使代碼與Spring接口耦合在一起,因此沒有特別的必要,建議不要直接訪問容器。 5,Bean實例的創建方式及對應配置: 創建Bean的方法: ①調用構造器創建Bean實例; ②調用靜態工廠方法創建Bean; ③調用實例工廠創建Bean。 調用靜態工廠方法創建Bean: class屬性是必須的,但此時的class並不是指定Bean實例的實現類而是靜態工廠類。采用靜態工廠類需要配置如下兩個屬性: class靜態工廠類的名字; factory-method工廠方法(必須是靜態的)。 如果靜態工廠的方法有參數通過<constructor-arg/>元素知道。 調用實例工廠方法創建Bean: 使用實例工廠Bean時class屬性無需指定,因Spring容器不會直接實例化該Bean, 創建Bean時需要如下屬性: factory-bean:該屬性為工廠Bean的ID; factory-method:該屬性是定實例工廠的工廠方法。 6,入理解Spring容器中的Bean: 抽象Bean: 所有的抽象Bean,就是是定abstract屬性為true的Bean,抽象Bean不能被實例化,抽象Bean的價值在於被繼承 使用子Bean: 隨著應用規模的增大,Spring配置文件的增長速度更快。當應用中的組件越來越多,,Spring中的Bean配置也隨之大幅度增加。 就會出現一中現象:有一批配置Bean的信息完全相同,只有少量 的配置不同。怎麽解決呢? 這時候就可以用Bean的繼承來解決。 註意:子Bean無法從父Bean繼承如下屬性: depends-on,aotuwirwe,dependency-check,singleton,scope,lazy-iniyt這些屬性總是子Bean定義,或采用默認值。 通過 為一個<bean.../> 元素指定parent屬性,即可指定該Bean是一個子Bean。 Bean繼承與java中繼承的區別: Spring中的子bean和父Bean可以是不同類型,但java中的繼承則可保證子類是一種特殊的父類; Spring中的Bean的繼承是實例之間的關系,因此只要表現在參數值的延續,而java中的繼承是類之間的關系,主要表現為方法、屬性之間的延續; Spring中的子Bean不可以作為父Bean使用,不具備多態性,java中的子類完全可以當成父類使用。 Bean的生命周期: ①singleton與prototype的區別: singleton:Spring可以精確的知道該Bean何時被創建、初始化、銷毀。對於singleton作用域的Bean,每次客戶端請求Spring容器總會返回一個共享的實例。 prototype:Spring容器僅僅負責創建Bean,當容器創建了Bean的實例後,Bean實例完全交給客戶端代碼管理,容器不在跟蹤其生命周期。 每次客戶端請求prototype作用域的Bean,都會為他創建一個新的實例, ②依賴關系註入後的行為: Spring提供兩種方法在Bean全部屬性設置成功後執行特定的行為: 使用init-method屬性; 該Bean實現InitializingBean接口 第一種方法:使用init-method屬性指定某個方法在Bean全部屬性依賴關系設置結束後自動執行。使用這種方法不需要將代碼與Spring的接口耦合在一起,代碼汙染少; 第二種方法:實現Initializing接口,該接口有一個方法void afterPropertiesSet() throws Exception,雖然實現次接口一樣可以在Bean全部屬性設置成功後執行特定的行為,但是汙染了代碼,是侵入式設計,因此不推薦使用。 註意:如果即采用init-method屬性指定初始化方法,又實現InitializingBean接口來指定初始化方法,先執行initializingBean接口中定義的方法,再執行init-method屬性指定的方法。 ③Bean銷毀之前行為: 與定制初始化相似,Spring也提供兩種方式定制Bean實例銷毀之前的特定行為,如下: 使用destroy-method屬性: 實現DisposableBean接口: 註意:如果即采用destroy-method屬性指定銷毀之前的方法,又實現DisposableBean接口來指定指定銷毀之前的方法,與②類似。 ④default-init-method與default-destroy-method屬性,指定了所有的Bean都會執行此方法,而不是單個的Bean。 協調作用域不同步的Bean: 描述: 當Spring容器中作用域不同的Bean相互依賴時,可能出現一些問題: 當兩個singleton作用域Bean存在依賴關系時,或當prototype作用依賴singleton作用域的Bean時,通過屬性定義依賴關系即可。、 但是,當singleton作用域的Bean依賴prototype作用域Bean時,singleton作用域的Bean只有一次初始化的機會,他的依賴關系也只有在初始化階段被設置,而他所依賴的prototype作用域的Bean則會不斷的產生新的Bean實例。 解決方案: 第一種:部分放棄依賴註入:singleton作用域的Bean每次需要prototype作用域的Bean,則主動向容器請求新的Bean實例。 第二種:利用方法註入。 第一種方案肯定是不好的,代碼主動請求新的Bean實例,必然會導致與Spring API耦合,造成代碼嚴重汙染。 通常情況下采用第二中方式。 方法註入通常使用lookup方法註入,利用lookup方法註入可以讓Spring容器重寫容器中Bean的抽象方法或具體方法,返回查找容器中的其他 Bean,被查找的Bean通常是non-singleton Bean(盡管也可以是singleton). 如:
public class SteelAxe implements Axe{
        //每執行一次加一
        private int count;
        public String  chop(){
            return ++count;
    }
}
public abstract class Chinese implements Perosom{
        private Axe axe;
//定義一個抽象方法,該方法將由Spring負責實現
        public abstract Axe createAxe();
        public voidsetAxe(Axe axe){
                this axe = axe;
        }
        public Axe getAxe(){
                return axe;
        }
}
在Spring配置文件中配置:
<bean id="steelAxe" class="...SteelAxe" scope="prototype"></bean>
 
<bean id="chinese" class="..Chinese" >
  < lookup-mehtod name="createAxe" bean="steelAxe">
    <property name="axe" ref="steelAxe"/>
</bean>
容器中的工廠Bean: 此處的工廠Bean與前面介紹的實例工廠方法創建Bean、靜態工廠創建Bean有所區別: 前面的那些工廠是標準的工廠模式,Spring只是負責調用工廠方法來創建Bean實例; 此處工廠Bean是Spring的一種特殊Bean,這種工廠Bean必須實現FactoryBean接口。 FactoryBean接口是工廠Bean標準的工廠Bean的接口,實現該接口的Bean只能當工廠Bean使用,當我們將工廠Bean部署在容器中,並通過getBean()方法來獲取工廠Bean,容器不會返回FactoryBean實例而是FactoryBean的產品。 FactoryBean提供了三個方法: Object getObject(); Class getObjectType(); boolean isSingleton(); 如:
public class PersonFactory implements FactoryBean{
    Person p = null;
    public Object getObject() throws Exception{
        if(p==null){
            p  = new Chinense();
            return p;
        }
    }
    public Class getObjectType(){
        return Chinese.class;
     }
 
    public boolean isSingleton(){
        return true;
    }
}
<!--配置一個FactoryBean,和普通的Bean一樣-->
<bean id="chinese" class=""/>
        public static void main(String args[]){                //以classpth下的bean.xml創建Reource對象
                ClassPathResource re = new ClasspathResource("bean.xml");
                //創建BeanFactory
                XmlBeanFactory factory = new XmlBeanFactory(re);
                Person p = (Person)factory.getBean("chinese");
                //如需要獲取FactoryBean本身則應該在bean id前加&
                Person p = (Person)factory.getBean("&chinese");
        }
對於初學者可能無法體會到工廠bean的作用,實際上,FactoryBean是Spring中非常有用的接口。例如:TransationProxyFactroyBean,這個工廠轉為目標Bean創建事務代理. 7,深入理解依賴關系配置 組件與組件之間的耦合,采用依賴註入管理,但是普通的javabean屬性值,應直接在代碼裏設置。 對於singleton作用域的bean,如果沒有強制取消其預初始化行為,系統會在創建Spring容器時預初始化所有的singleton作用域的bean,與此同時,該bean依賴的bean也一起被實例化。 BeanFactory與ApplicationContext實例化容器中的bean的時機不同,前者等到程序需要Bean實例才創建Bean 後者會預初始化容器中的所有Bean。 因為采用ApplicationContext作為Spring的容器,創建容器時,會創建容器中所有singleton作用域的所有bean,因此可能需要更多的系統資源,但是一旦創建成功。應用後面的 響應速度會很快,因此,對於普通的javaEE而言 ,建議使用ApplicationContext作為Spring的容器。 Bean實例4中屬性值的設置: value;ref;bean;list、set、map、props ①設置普通屬性值value,略; ②配置合作者Bean ref 可以為ref元素指定兩個屬性:bena、Local bean:引用在不同一份XML配置文件中的其他Bean實例的ID屬性值; Local:引用同一份XML配置文件的其他Beanid屬性值。 也可以不配置以上兩個屬性。 ③組合屬性名稱:
public class  A{
    private Person p = new Person();
    set/get....
}
Spring配置文件
<bean id="a" class="A">
    <property name="p.name" value="aaa"/>
</bean>
④註入嵌套Bean:
<bean id="" class="">
       < property name="">
                //屬性為嵌套Bean 不能由Spring容器直接訪問,因此沒有id屬性
                <bean class="..."/>
        </property>
</bean>
⑤註入集合值:
<list>
<value></value>
<value></value>
</list> 
<map>
//每一個entry配置一個key-value對
<entry>
    <key>
        <value>.</value>
    </key>
    <value></value>
</entry>
</map>
 
<set>
    <value></value>
    <bean></bean>
    <ref local=""/>
</set>
 
<props>
    <prop key="">.....</prop>
    <prop key="">.....</prop>
</props>
⑥註入方法返回值:
public class ValueGenrator{
    public int getValue(){
        return 6;
    }
    public static int getStaticValue(){
        return 9;
    }
}
<bean id="valueGenrator" class="lee.ValueGenrator"/>
<bean id="son1" class="Son">
    <property name="age">
        <bean class="org.springframework.bean.factory.congfig.MethodInvokignFactoryBean">
//配置非靜態方法
            <property name="targetObject" ref="valueGenrator"/>
//配置靜態方法
<!--
            <property name="targetClass" value="lee.ValueGenrator"/>
-->
            <property name="targetMehtod" value="getStaticValue/>
</property>
</bean>
8,強制初始化Bean: Spring有一個默認的規則,總是先初始化主調Bean,然後在初始化依賴Bean。 為了指定Bean在目標Bean之前初始化,可以使用depends-on屬性 9,自動裝配: Spring能自動裝配Bean與Bean之間的依賴關系,即使無需使用ref顯式指定依賴Bean。 Spring的自動裝配使用autowire屬性指定,每一個<bean/>元素都可以指定autowire屬性,也就是說在Spring容器中完全可以讓某些Bean自動裝配,而某些Bean不沒使用自動裝配。 自動裝配可以減少配置文件的工作量,但是降低了依賴關系的透明性和依賴性。 使用autowire屬性自動裝配,autowire屬性可以接受如下幾個值 : no:不使用自動裝配。這是默認配置。 byName:根據屬性自動裝配,BeanFactory會查找容器中所有的Bean,找出id屬性與屬性名同名的Bean來完成註入。如果沒有找到匹配的Bean,Spring則不會進行任何註入。 byType:根據屬性類型自動裝配,BeanFactroy會查找容器中所有的 Bean,如果一個正好與依賴屬性類型相同的Bean,就會自動註入這個屬性。 如果有多個這樣的Bean則會拋出異常。如果沒有這樣 的Bean則什麽也不會發生,屬性不會被設置。 constructor:與byType類似,區別是用於構造註入的參數,如果BeanFactory中不是恰好有一個Bean與構造器參數類型相同。則會拋出異常。 autodetect:BeanFactory會根據Bean內部的結構,決定使用constructor或byType,如果找到一個缺省的構造器,就會應用byType。 註意:對於大型的應用而言,不鼓勵使用自動裝配, 10,依賴檢查: Spring提供一種依賴檢查的功能,可以防止出現配置手誤,或者其他情況的錯誤。 使用依賴檢查可以讓系統判斷配置文件的依賴關系註入是否完全有效。 使用依賴檢查,可以保證Bean的屬性得到了正確的設置,有時候,某個Bean的特定屬性並不需要設置值,或者某些屬性已有默認值,此時采用依賴檢查就會出現錯誤,該Bean就不應該采用依賴檢查,幸好Spring可以為不同的Bean單獨指定依賴檢查的行為,Spring提供dependency-chech屬性來配置依賴檢查,當然也可以指定不同的檢查依賴策略。 該屬性有如下值: none:不進行依賴檢查,沒有指定值的Bean屬性僅僅是沒有設置值,這是默認值。 simple:對基本類型和集合(除了合作者Bean)進行依賴檢查。 objects:僅對合作者Bean進行依賴檢查。 all:對合作者Bean、基本數據類型全部進行依賴檢查。
public class Chinese implements Person{
        private Axe axe;
        private int age = 30;
            //implements method 
 
        public void setAge(int age){
            this.age = age;
        }
        public int getAge(){
            return age
        }
}
<bean id="axe" class="StoneAxe"/>
<bean id="chinese" class="Chinese" dependency-check="all">
    <property name="axe" ref="axe"/>
</bean>
以上程序將會拋出異常,雖然Chinese類的age屬性已經有了默認值,但配置dependency-check="all"則要求配置文件為所有的屬性都提供正確的值。 而age屬性沒有提供值。

spring的基本用法