JavaBean 是一種JAVA語言寫成的可重用元件。
為寫成JavaBean,類必須是具體的和公共的,并且具有無參數的構造器。
JavaBean 通過提供符合一緻性設計模式的公共方法将内部域暴露成員屬性。
例
以下是一個簡單的JavaBean類。
定義一個Person類,有 name 和 age 兩個屬性,以及這兩個屬性的 get、set 方法。
<a></a>
package com.demo.web.controllers;
public class Person {
private String name = "zhangsan";
private int age = 28;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
public String getName() {
return name;
public void setName(String name) {
public int getAge() {
return age;
public void setAge(int age) {
}
JavaBean 是一個 public 類型的類
JavaBean 含無參數的構造函數
JavaBean 提供 set 和 get 方法
傳統JavaBean生命周期
傳統的Java應用,Bean的生命周期很簡單。
使用new進行執行個體化,然後該Bean就可以使用了。程式結束後,Java會自動進行垃圾回收。
Spring容器中的JavaBean生命周期
在Spring容器中的Bean的生命周期要複雜多了,步驟如下:
(1)Spring對Bean進行執行個體化。
(2)Spring将值和Bean的引用注入進Bean對應的屬性中。
(3)如果 Bean 實作了 BeanNameAware 接口,Spring将 Bean 的ID傳遞給 setBeanName() 接口方法。
(4)如果 Bean 實作了 BeanFactoryAware 接口,Spring将調用 setBeanFactory() 接口方法,将BeanFactory 容器執行個體傳入。
(5)如果 Bean 實作了 ApplicationContextAware 接口,Spring将調用 setApplicationContext() 接口方法,将應用上下文的引用傳入。
(6)如果 Bean 實作了 BeanPostProcessor 接口,Spring将調用它們的 post-ProcessBeforeInitialization接口方法。
(7)如果 Bean 實作了 InitializingBean 接口,Spring将調用它們的 afterPropertiesSet 接口方法。類似地,如果 Bean 使用 init-method 聲明了初始化方法,該方法也會被調用。
(8) 如果 Bean 實作了 BeanPostProcessor接口,Spring将調用它們的 post-ProcessAfterInitialization接口方法。
(9)此時此刻,Bean 已經準備就緒,可以被應用程式是用來,它們将一直駐留在應用上下文中,直到該應用上下文被銷毀。
(10)如果 Bean 實作了 DisposableBean 接口,Spring将調用它的 destroy() 接口方法。同樣,如果Bean使用 destroy-method 聲明了銷毀方法,該方法也會被調用。
建立應用對象之間協作關系的行為通常被稱為裝配,這也是依賴注入的本質。
Spring是一個基于容器的架構。但是如果沒有配置Spring,那它就是一個空容器,當然也毫無用處。
是以需要配置Spring,以告訴容器需要加載哪些Bean和如何裝配這些Bean。
從Spring3.0開始,Spring容器提供了兩種配置Bean的方式。
使用XML檔案作為配置檔案
基于Java注解的配置方式
注:本文先不介紹注解的配置方式,而是重點介紹傳統的XML配置方式。
以下是一個典型的XML配置檔案(一般為<servlet名>-servlet.xml檔案)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Bean declarations go here -->
</beans>
在 <beans> 元素内,可以放置所有的Spring配置資訊。
實際上,beans這個标簽是 Spring的一種命名空間。
Spring架構自帶了10個命名空間,如下表所示:
命名空間
用途
aop
為聲明切面以及将@AspectJ注解的類代理為Spring切面提供了配置元素
beans
支援聲明Bean和裝配Bean,是Spring最核心也是最原始的命名空間
context
為配置Spring應用上下文提供了配置元素,包括自動檢測盒自動裝配Bean、注入非Spring直接管理的對象
jee
提供了與Java EE API的內建,例如JNDI和EJB
jms
為聲明消息驅動的POJO提供了配置元素
lang
支援配置由Groovy、Jruby或BeanShell等腳本是實作的Bean
mvc
啟用SpringMVC的能力,例如面向注解的控制器、試圖控制器和攔截器
oxm
支援Spring的對象到XML映射配置
tx
提供聲明式事務配置
util
提供各種各樣的工具類元素,包括把集合配置為Bean、支援屬性占位符元素
除了Spring架構自帶的命名空間,Spring Portfolio的許多成員,例如Spring security、Spring Web Flow和Spring Dynamic Modules,同樣提供了他們自己的命名空間配置。
以上文提到的Person 類為例,定義了JavaBean後,還需要在xml檔案中聲明,形式如下:
<bean id="person" class="com.demo.web.controllers.Person"/>
這個标簽的意思就是,建立一個 com.demo.web.controllers.Person 類的對象person。
當Spring容器加載這個Bean的時候,會使用預設構造器來執行個體化person對象,相當于:
com.demo.web.controllers.Person person = new com.demo.web.controllers.Person();
備注實際上,Spring是使用反射機制來建立Bean的。
很多應用場景下,我們希望在初始化執行個體時,傳入關鍵性的參數,這就需要帶參數的構造函數了。
為了解決這個問題,在構造Bean的時候,可以使用 <constructor-arg> 元素來指定構造器參數。
<bean id="person" class="com.demo.web.controllers.Person">
<constructor-arg value="lisi" />
<constructor-arg value="28" />
</bean>
如果不使用這個标簽,spring将使用預設構造函數。
以上參數都是直接傳入值,如果想傳入對象引用,那要怎麼做呢?
請參考下面的例子:
首先定義一個Car類
public class Car {
private String model;
public Car() {
public Car(String model) {
this.model = model;
public void run() {
System.out.println(model + " 正在行駛");
再定義一個Driver類
public class Driver {
private Car car;
public Driver() {
public Driver(Car car) {
this.car = car;
public void drive() {
car.run();
接下來,我們可以在XML中配置一個Car的變量
<bean id="car" class="com.demo.web.controllers.Car">
<constructor-arg value="寶馬5系" />
有了Car的變量car,我們就可以在聲明Driver變量時,使用 <constructor-arg> 标簽引用它。
<bean id="driver" class="com.demo.web.controllers.Driver">
<constructor-arg ref="car" />
有時候一個類并沒有public型的構造方法(典型的如單例模式裡的類),對于這種情況如何在spring中執行個體化呢?
這時候靜态工廠方法是執行個體化對象的唯一方法。Spring支援通過 <bean> 元素的 factory-method 屬性來裝配工廠建立的Bean。
public class Singleton {
static Singleton instance = new Singleton();
private Singleton() {
public static Singleton getInstance() {
return instance;
為了在Spring中将Singleton配置為Bean,可以按照下面的方式來配置
<bean id="instance" class="com.demo.web.controllers.Singleton"
factory-method="getInstance" />
所有的Spring Bean預設都是單例。當容器配置設定一個Bean時,它總是傳回Bean的同一個執行個體。
但有時我們需要每次請求時都獲得唯一的Bean執行個體,如何做到呢?
當在Spring中配置 <bean> 元素時,我們可以為Bean聲明一個作用域。為了讓Spring在每次請求時都為Bean産生一個新的執行個體,我們隻需要配置Bean的scope屬性為 prototype即可。
<bean id="person" class="com.demo.web.controllers.Person" scope="prototype" />
除了prototype,Spring還提供了其他幾個作用域選項,如下:
作用域
定義
singleton
在每一個Spring容器中,一個Bean定義隻有一個對象執行個體(預設)
prototype
運作Bean的定義可以被執行個體化任意次(每次調用都建立一個執行個體)
request
在一次HTTP請求中,每個Bean定義對應一個執行個體,該作用域僅在基于Web的Spring上下文(例如Spring MVC)中才有效
session
在一個HTTP Session中,每個Bean定義對應一個執行個體,該作用域僅在基于Web的Spring上下文(例如Spring MVC)中才有效
global-session
在一個全局HTTP Session中,每個Bean定義對應一個執行個體,該作用域僅在Portlet上下文中才有效
注:Spring的單例Bean隻能保證在每個應用上下文中隻有一個Bean的實 例。
當執行個體化一個Bean時,可能需要執行一些初始化操作來確定該Bean處于可用狀态。同樣地,當不再需要Bean,将其從容器中移除時,我們可能還需要按 順序執行一些清除工作。為了滿足初始化和銷毀Bean的需求,Spring提供了Bean生命周期的鈎子方法。
為Bean定義初始化和銷毀操作,隻需要使用 init-method 和 destroy-method 參數來配置 <bean> 元素。 init-method 屬性指定了在初始化 Bean 時要調用的方法。類似地,destroy-method 屬性指定了 Bean 從容器移除之前要調用的方法。
假設,為一個燈泡的功能寫一個類。
public class Light {
public void turnOn() {
// ...
public void turnOff() {
接着,我們在XML中做如下配置
<bean id="light" class="com.demo.web.controllers.Light"
init-method="turnOn" destroy-method="turnOff" />
這樣,就能保證讓燈泡類在點亮之前調用turnOn(),結束時調用turnOff()。
通常,JavaBean中的屬性都是私有的,同時提供一組get、set方法。
(1)注入簡單值
在Spring中,除了用前面介紹的構造器注入方式,還可以使用 <property> 元素配置 Bean 的屬性。
還是以Person類為例
<property name="name" value="wangwu" />
<property name="age" value="30" />
(2)引用其他Bean
還記得我們在構造器注入部分提到的Driver和Car類的例子嗎,如果使用property的方式,則按如下方式表達
<bean id="baoma" class="com.demo.web.controllers.Car">
<property name="car" ref="baoma" />
(3)内部注入
内部注入是通過直接聲明一個 <bean> 元素作為 <property>元素的子節點而定義的。
<property name="car">
<bean class="com.demo.web.controllers.Car" />
</property>
(4)使用Sping的命名空間p裝配屬性
Spring還提供了一個命名空間p以簡化<property>元素的裝配方式。
命名空間p的schema URI為 http://www.springframework.org/schema/p。
如果要使用命名空間p ,需要在Spring的XML配置中增加一段聲明
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
有了以上聲明,我們就可以使用p:作為<bean>元素所有屬性的字首來裝配Bean的屬性。
用p:重新定義上節Driver類的配置, 如下:
<bean id="driver" class="com.demo.web.controllers.Driver"
p:car-ref="baoma"/>
p:car-ref="baoma" 表示要裝配car 屬性,-ref字尾表示這是一個引用而不是字面值。"baoma"是這個屬性的引用對象。
Spring不僅可以裝配單個值,也可以裝配集合。
Spring提供4種類型的集合配置元素。
集合元素
對應實際資料類型
<list>
裝配list類型的值,允許重複
數組或java.util.Collection
<set>
裝配set類型的值,不允許重複
<map>
裝配map類型的值,名稱和值可以是任意類型
java.util.Map
<props>
裝配properties類型的值,名稱和值必須都是String型
java.util.Properties
(1)<list> 和 <set>
<list> 和 <set> 都可以用來裝配類型為 java.util.Collection 的任意實作或數組的屬性。
兩者的差別在于:list 允許成員重複; set 必須保證成員不重複。
需要注意的是,不是說如果屬性是java.util.Set 類型,則使用者必須用 <set> 裝配。
定義一個 instruments 屬性,它是一個Collection,儲存各種樂器
<property name="instruments">
<list>
<ref bean="guitar" />
<ref bean="piano" />
</list>
</property>
<set>
<ref bean="piano" /><!-- 自動忽略重複的屬性 -->
</set>
(2)<map>
<map> 元素聲明了一個 java.util.Map 類型的值。每個 <entry> 元素定義 Map 的一個成員。
<entry> 元素由一個鍵和一個值組成,鍵和值可以是簡單類型,也可以是其他Bean的引用。
屬性
key
指定map中entry的鍵為String
key-ref
指定map中entry的鍵為Spring上下文中其他Bean的引用
value
指定map中entry的值為String
value-ref
指定map中entry的值為Spring上下文中其他Bean的引用
<map>
<entry key="GUITAR" value-ref="guitar">
<entry key="PIANO" value-ref="piano">
</map>
(3)<prop>
如 果 Map 的每一個 entry 的鍵和值都為 String 類型時,可以考慮使用 java.util.Properties 代替 Map。Properties 類提供了和 Map 大緻相同的功能,但是它限定了鍵和值必須為 String 類型。
<props> 元素建構了一個 java.util.Properties 值,這個 Properties 的每一個成員由 <prop> 定義。
<props>
<prop key="GUITAR">guitar sound</prop>
<prop key="PIANO">piano sound</prop>
</props>
Spring 3引入了Spring表達式語言(Spring Expression Lanuage, SpEL)。
它通過運作期執行的表達式将值裝配到 Bean 的屬性或構造器參數中。
SpEL 表達式的首要目标是通過計算獲得某個值。最簡單的SpEL求值或許是對字面值、Bean的屬性或某個類的常量進行求值。
字面值
<property> 元素的 value 屬性中使用 #{} 界定符把這個值裝配到 Bean 的屬性中
<property name="count" value="#{5}" />
此外,也可以與非SpEL 表達式的值混用
<property name="count" value="The value is #{5}" />
引用Bean、Properties 和方法
SpEL 表達式可以通過 ID 引用其他 Bean。
<property name="fruit" value="#{apple}" />
這和以下語句的功能等價
<property name="fruit" ref="apple" />
除了直接引用其他Bean,也可以引用 Bean 對象的屬性和方法
<property name="song" value="#{singer.song}" />
<property name="song" value="#{singer.selectSong().toUpperCase()}" />
需要注意的是,singer.selectSong().toUpperCase()存在一個問題,如果selectSong()方法傳回的是null, 那麼SpEL表達式求值時會抛出一個 NullPointerException 異常。
為了避免這種情況,可以使用null-safe存取器(?.)
<property name="song" value="#{singer.selectSong()?.toUpperCase()}" />
使用 ?. 代替 . 來通路 toUpperCase() 方法。?. 可以確定隻有當 selectSong() 不為 null 時才去調用 toUpperCase() 方法。
操作類
現在,我們了解了在 SpE L中,如何去調用 Bean 對象,以及對象的屬性和方法。
但是,如何去通路類的靜态方法或常量引用呢?
在 SpEL 中,使用 T() 運算符去調用類作用域的方法和常量。
以下示範了如何調用 java.lang.Math 類中的靜态方法和屬性。
<property name="multiplier" value="#{T{java.lang.Math}.PI}" />
<property name="multiplier" value="#{T{java.lang.Math}.random}" />
在 SpEL 值上執行運算操作
SpEL提供了幾種運算符,這些運算符可以用在SpEL表達式中的值上。
運算符類型
運算符
算術運算
+、-、*、/、%、^
關系運算
<、>、==、<=、>=、lt、gt、eq、le、ge
邏輯運算
and、or、not、|
條件運算
?: (ternary)、?: (Elvis)
正規表達式
matches
假設針對前面的Person類,我們定義一個List集合,如下:
<util:list id="persons">
<bean class="com.demo.web.controllers.Person" p:name="zhangsan" p:age="17"/>
<bean class="com.demo.web.controllers.Person" p:name="lisi" p:age="24"/>
<bean class="com.demo.web.controllers.Person" p:name="wangwu" p:age="30"/>
<bean class="com.demo.web.controllers.Person" p:name="zhaoliu" p:age="16"/>
<bean class="com.demo.web.controllers.Person" p:name="liuqi" p:age="23"/>
</util:list>
通路集合成員
可以使用 [] 運算符來通路集合成員
<property name="choosePerson" value="#{persons[T{java.lang.Math}.random() * persons.size()]]}" />
以上表示,随機選取一個人。
也可以按下面方式選取
<property name="choosePerson" value="#{persons['zhangsan']}" /><!-- 選取集合中叫張三的人 -->
<property name="choosePerson" value="#{persons[2]}" /><!-- 選取集合中第二個人 -->
查詢集合成員
如果想要在persons集合中查詢年齡大于18歲的人。
在SpEL中,隻需使用一個查詢運算符(.?[]) 就可以簡單做到,如下所示:
<property name="adults" value="#{persons.?[age gt 18]}" />
查詢運算符會建立一個新的集合,集合中隻存放符合括号中表達式的成員。
SpEL 還提供兩種運算符:.^[] 和 .$[],從集合中查詢出第一個比對項和最後一個比對項。
投影集合
在SpEL中, 提供了投影運算符(.![])将集合中每個成員的特定屬性放入一個新的集合中。
<property name="personNames" value="#{persons.![name]}" />
以上,将所有人的名字取出來,建立一個新的集合personNames。
打開 HelloWorld 工程。
(1)建立一個 java 檔案,名為 Person.java,完整内容如下:
View Code
(2)修改 index.jsp 檔案,完整内容如下:
(3)運作
結果如下:
本文轉自靜默虛空部落格園部落格,原文連結:http://www.cnblogs.com/jingmoxukong/p/4532680.html,如需轉載請自行聯系原作者