Bean的配置一共有兩種方式:一種是基於XML文件的方式,另一種是基於注解的方式。
本文主要介紹基於XML文件的方式
<bean id="helloWorld" class="com.sevenhu.domain.HelloWorld"> <property name="userName" value="Spring"></property> </bean>
上面的配置代碼中:
id:Bean的名稱,在IOC容器中必須是唯一的,若id,沒有指定,那么Spring自動將類名作為Bean的名字,id可以指定多個名字,名字之間可用逗號,分 號,或空格分隔。
Spring容器
在Spring IOC容器讀取Bean配置創建Bean實例之前,必須對它進行實例化,只有在容器實例化之后,才可以從IOC容器里獲取Bean的實例並使用。
Spring提供了兩種類型的IOC容器實現
-BeanFactory:Ioc容器的基本實現。
-ApplicationContext:提供了更多的高級特性。是BeanFactory的子接口。
-BeanFactory是Spring框架的基礎設施,面向Spring本身;ApplicationContext面向使用Spring框架的開發者。
ApplicationContext主要有兩個實現類:
-ClassPathXmlApplicationContext:從類路徑下加載配置文件。
-FileSystemXmlApplicationContext:從文件系統中加載配置文件。
ApplicationContext在初始化上下文時就實例化所有單例的bean。
屬性注入:
即通過setter方法注入bean的屬性值或依賴的對象。屬性注入使用<property>元素,使用name屬性值指定bean的屬性名稱,value屬性指定屬性值。使用這種注入方式,那么bean中必須有一個默認的構造函數,即無參的構造函數。
eg: <property name="userName" value="Spring"></property>
構造方法注入:
按索引匹配入參:
<bean id="car" class="com.sevenhu.domain.Car"> <constructor-arg value="長春一汽" index="0"></constructor-arg> <constructor-arg value="2000" index="1"></constructor-arg> <constructor-arg value="奧迪" index="2"></constructor-arg> </bean>
按類型匹配入參:
<bean id="car2" class="com.sevenhu.domain.Car"> <constructor-arg value="長春一汽" type="java.lang.String"></constructor-arg> <constructor-arg value="2000" type="double"></constructor-arg> <constructor-arg value="奧迪" type="java.lang.String"></constructor-arg> </bean>
注:字面值都可用字符串表示,可以通過<value>元素標簽或value屬性進行注入。基本數據類型及其封裝類,String等類型都可以采用字面值注入的方 式。
如果一個bean的某一個屬性是一個對象,可使用如下配置:
<bean id="people" class="com.sevenhu.domain.People"> <property name="name" value="hujingwei"></property> <property name="car" ref="car2"></property> </bean>
或者使用內部類:
<bean id="people1" class="com.sevenhu.domain.People"> <property name="name" value="zhangsongzhu"></property> <property name="car"> <!--內部bean,不能被外部的bean所引用,因此沒有必要設置id--> <bean class="com.sevenhu.domain.Car"> <property name="brand" value="Ford"></property> <property name="creator" value="SomeOne"></property> <property name="price" value="100000"></property> </bean> </property> </bean>
可以使用專用的<null/>元素標簽為Bean的字符串或其它對象的屬性值注入null值,如下:
<bean id="people2" class="com.sevenhu.domain.People"> <property name="name" value="hu"></property> <!--若某一個bean的屬性值需要設置為null--> <property name="car"><null/></property> </bean>
使用p命名空間:
為了簡化XML文件的配置,越來越多的XML文件使用屬性而非子元素配置信息,因此Spring自從2.5之后就引入了一個p命名空間,可以通過<bean>元素屬性的方式配置Bean的屬性
<!--使用p命名空間--> <bean id="people3" class="com.sevenhu.domain.People" p:name="seven" p:car-ref="car1"> </bean>
XML配置里的Bean自動裝配
Spring IOC容器可以自動裝配bean,需要做的僅僅是在<bean>的autowire屬性中指定自動裝配的模式,具體的裝配模式如下:
-byType(根據類型裝配):若IOC容器中有多個與目標bean類型一致的bean,在這種情況下,Spring將無法判定哪個bean最適合該屬性,所以不能進行自動裝配。
-byName(根據名稱自動裝配):必須將目標bean的名稱和屬性名設置的完全相同。
自動裝配的缺點:在bean配置文件里設置autowire屬性進行自動裝配將會裝配bean的所有屬性,然而,若只希望裝配個別屬性,autowire不夠靈活;autowire屬性要么根據類型裝配,要么根據名稱裝配,不能兩者兼而有之。
繼承bean配置
Spring允許繼承bean的配置,被繼承的bean稱為父bean,繼承這個bean的bean為子bean。子bean從父bean中繼承配置,包括bean的屬性配置,子bean也可以覆蓋從父bean繼承過來的配置,父bean可以作為配置模版,也可以作為bean實例,若指向把父bean作為模版,可以設置bean的abstract屬性為true,這樣Spring就不會實例化這個bean。並不是父bean中所有的屬性都會被繼承,比如:autowire,abstract等;也可以忽略父bean的class屬性,讓子bean指定自己的類,而共享相同的屬性配置,但是此時abstract必須設為true。
<bean id="user" class="com.*.*"> <property name="userName" value="hu"/> </bean> <bean id="user1" parent="user"> <property name="userName" value="hu"/> </bean> <bean id="user2" parent="user"> <property name="userName" value="hu"/> </bean>
依賴bean配置:
Spring允許用戶通過depends-on屬性設定bean前置依賴的bean,前置依賴的bean會在bean實例化之前創建好,如果前置依賴多個bean,則可以通過逗號,空格的方式配置bean的名稱。
<bean id="user3" depends-on="user1"> </bean>
bean的作用域(通過<bean>標簽的scope屬性設置)
-singleton 在Spring IOC容器中只存在一個bean實例,bean以單例的方式存在(默認的作用域)
-prototype 每次調用getBean()時都會返回一個新的實例
-request 每次HTTP請求都會返回一個新的bean,該作用域僅適用於WebApplicationContext環境中
-session 在session中共享一個bean,該作用域僅適用於WebApplicationContext環境中
使用外部屬性文件:
首先外部文件db.properties的內容如下:
jdbc.user=root jdbc.password=1230 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql:///test jdbc.initPoolSize=5 jdbc.maxPoolSize=10
那么在配置文件中配置如下:
<!-- 導入外部的資源文件 --> <context:property-placeholder location="classpath:db.properties"/> <!-- 配置數據源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property> <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property> </bean>
IOC容器中Bean的生命周期
-通過構造器或工廠方法創建bean實例
-為bean的屬性設置值和對其它bean的引用
-調用bean的初始化方法
-bean可以使用了
-當容器關閉的時候,調用bean的銷毀方法。
注:當bean的聲明里設置init-method和destroy-method屬性,為bean指定初始化和銷毀方法(這兩個方法一般都沒有參數)
創建bean的后置處理器
bean后置處理器允許在調用初始化方法前后對bean進行額外的處理,bean后置處理器對IOC容器里所有bean實例逐一處理,而非單一實例。對bean的后置處理器而言,需要實現
Interface BeanPostProcessor接口,在初始化方法被調用前后,Spring將把每個bean實例分別傳遞給BeanPostProcessor接口的以下兩個方法:
postProcessorAfterInitialization(Object bean,String beanName); postProcessorBeforeInitialization(Object bean,String beanName);
添加后置處理器后Bean的生命周期
-通過構造器或工廠方法創建bean實例
-為bean的屬性設置值和對其它bean的引用
-將bean實例傳遞給后置處理器的postProcessorBeforeInitialization(Object bean,String beanName);方法
-調用bean的初始化方法
-將bean實例傳遞給后置處理器的postProcessorAfterInitialization(Object bean,String beanName);方法
-bean可以使用了
-當容器關閉的時候,調用bean的銷毀方法。
代碼如下:
package com.sevenhu.domain; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by hu on 2016/4/1. */ public class MyBean implements BeanPostProcessor { //該方法在bean的初始化方法之前調用 @Override public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { //o就是bean實例對象,s就是bean實例的id System.out.println("before initialication ...."); //返回bean的實例對象 return o; } //該方法在bean的初始化方法之后調用 @Override public Object postProcessAfterInitialization(Object o, String s) throws BeansException { System.out.println("after initialication ...."); return o; } public static void main(String[] args){ ApplicationContext applicationContext=new ClassPathXmlApplicationContext("beans.xml"); } }
配置代碼如下:
<!--配置bean后置處理器:不需要配置id屬性,IOC容器會識別到它是一個bean后置處理器,並調用其方法--> <bean class="com.sevenhu.domain.MyBean"></bean>
通過調用靜態工廠方法創建bean
調用靜態工廠方法創建bean是將對象創建的過程封裝到靜態方法中,當客戶端需要對象時,只需要簡單地調用靜態方法,而不關心創建對象的細節。
直接上代碼,工廠如下:
<!-- 通過工廠方法的方式來配置 bean --> <!-- 1. 通過靜態工廠方法: 一個類中有一個靜態方法, 可以返回一個類的實例(了解) --> <!-- 在 class 中指定靜態工廠方法的全類名, 在 factory-method 中指定靜態工廠方法的方法名 --> <bean id="dateFormat" class="java.text.DateFormat" factory-method="getDateInstance"> <!-- 可以通過 constructor-arg 子節點為靜態工廠方法指定參數 --> <constructor-arg value="2"></constructor-arg> </bean> <!-- 2. 實例工廠方法: 先需要創建工廠對象, 再調用工廠的非靜態方法返回實例(了解) --> <!-- ①. 創建工廠對應的 bean --> <bean id="simpleDateFormat" class="java.text.SimpleDateFormat"> <constructor-arg value="yyyy-MM-dd hh:mm:ss"></constructor-arg> </bean> <!-- ②. 有實例工廠方法來創建 bean 實例 --> <!-- factory-bean 指向工廠 bean, factory-method 指定工廠方法(了解) --> <bean id="datetime" factory-bean="simpleDateFormat" factory-method="parse"> <!-- 通過 constructor-arg 執行調用工廠方法需要傳入的參數 --> <constructor-arg value="1990-12-12 12:12:12"></constructor-arg> </bean>