Spring學習筆記一

Spring學習筆記》

第一章 裝配Bean

一、 聲明bean

1. 聲明一個簡單的bean

Spring3.0開始,提供xml和註解兩種配置Bean的方式。

以下爲xml配置文件聲明一個Bean:

<bean id=”bean_id” class=”bean_class”/>

id屬性定義了bean的名字,class屬性定義了bean的類。當Spring容器加載該bean時,Spring將使用默認的構造方法來實例化該bean

2. 通過構造方法聲明一個Bean

假設Bean中有一個帶參數的構造方法,可以通過xml配置該bean使用帶參數的構造方法實例化。

Bean代碼:

package com.model

 

public class MyBean{

private int age;

public MyBean(int age)

{this.age=age;}

public void setAge(int age)

{this.age=age;}

public int getAge()

{return age;}

}

 

Xml文件:

<bean id=mybean class=com.model.MyBean >

<constructor-arg  value=18 />

</bean>

3. 通過構造方法引用對象

如果bean的構造方法參數是對象,則可以通過xml文件配置。假設上例中構造方法參數爲對象,示例配置如下:

<bean id=mybean  class=com.model.MyBean>

<constructor-arg  ref=object/>

</bean>

 

4. 通過工廠方法創建Bean

有時候靜態工廠方法是實例化對象的唯一方法。Spring支持通過<bean>元素的factory-method屬性來裝配工廠創建的Bean

假設工廠方法爲

public static Instance getInstance()

{return new Instance();}

xml配置爲:

<bean id=mybean   class=com.model.MyBean >

<factory-method =getInstance />

5. Bean的作用域

所有的Spring  Bean默認都是單例。當容器分配一個Bean時,它總是返回Bean的同一個實例。

Spring中配置<bean>元素時,我們可以爲bean聲明一個作用域,爲了讓Spring在每次請求時都獲得一個新的Bean實例,只需要配置beanscope屬性爲prototype即可。

<bean id=mybean  class=com.model.MyBean   scope=prototype />

Spring還提供了其他的作用域選項,如下所示

作用域

定義

singleton

在每一個Spring容器中,一個bean定義只有一個實例對象(默認)

prototype

每次調用都創建一個實例

request

在一次http請求中,每個bean定義對於一個實例,該作用域僅在基於web的上下文中才有效

session

在一個http session中,每個bean定義對應一個實例,該作用域僅在基於web的上下文中才有效

global-session

在一個全局http session中,每個bean對應一個實例,該作用域僅在portlet上下文中才有效

6. 初始化和銷燬Bean

bean定義初始化和銷燬操作,只需要使用init-methoddestory-method參數來配置<bean>元素。init-method屬性指定了在初始化bean時要調用的方法。destory-method屬性指定了bean從容器移除之前要調用的方法。

示例:

<bean id=mybean  class=com.model.MyBean 

init-method=initMethod  destory-method=destoryMethod />

使用這種配置,bean在實例化之後會立即調用initMethod方法,在該bean從容器移除和銷燬前,會調用destoryMethod方法。

如果上下文中定義的很多bean都擁有相同名字的初始化方法和摧毀方法,可以使用<beans>元素的default-init-methoddefault-destory-method屬性:

<beans>

……………………

default-init-method=default-init-method

default-destory-method=default-destory-method</beans>

7. lazy-init

bean元素中可以設定lazy-init="true",這樣這個bean可以不跟隨容器啓動而初始化,而是在需要用到這個bean的時候再初始化。

二、 注入bean屬性

通常JavaBean的屬性是私有的,同時擁有一組getset方法。Spring可以藉助屬性的set方法來配置屬性的值,以實現setter方式的注入。

1. 注入簡單值

spring中可以使用<property>元素配置bean的屬性。<property>在許多方面都與<constructor-arg>類似,只不過一個是通過構造參數來注入值,另一個是通過調用屬性的setter方法來注入值。

例如:

<bean id=mybean  class=com.model.MyBean  >

<property name=arg value=arg_value>

</bean>

一旦bean被實例化,spring就調用<property>元素所指定屬性的setter方法爲該屬性注入值。value屬性可以指定數值型(intfloatDouble等)、booleanString型的值。

 

2. 引用其他bean

假設mybean1mybean引用,

<bean id=mybean1  class=com.model.MyBean1/>

<bean id=mybean   class=com.model.MyBean  >

<property  name=arg  ref=mybean1>

</bean>

3. 注入內部bean

內部bean是定義在其他bean內部的bean

例如:

<bean id=mybean class=com.model.MyBean>

<property  name=arg>

<bean class=com.model.MyBean1/>

</property>

</bean>

內部bean並不僅限於setter注入,還可以把內部bean裝配到構造方法的入參中,如下所示:

 

<bean id=mybean  class=com.model.MyBean>

<constructor-arg>

<bean class=com.model.MyBean1/>

</constructor-arg>

</bean>

注意內部bean沒有id屬性,雖然爲內部bean配置一個id屬性是完全合法的,但是並沒有太大必要,因爲我們永遠不會通過名字來引用內部bean。內部bean最大的缺點是他們不能被複用。內部bean僅適用於一次注入,而且不能被其他bean引用。

4. 使用Spring命名空間P裝配屬性

命名空間pschema URI http://www.springframework.org/schema/p   使用命名空間p,需要在xml文件中增加如下一段聲明:

xmlns:p=” http://www.springframework.org/schema/p

命名空間p使用示例:

<bean  id=mybean  class=com.model.MyBean

p:arg1=value1

p:arg2=value2

p:arg3-ref=object  />

5. 裝配集合

valueref僅在bean的屬性值是單個值的情況下才有用。當bean的屬性值是複數時,如集合時,可以使用集合配置。

Spring提供了相應的集合配置元素

集合元素

用途

<list>

裝配list類型的值,允許重複

<set>

裝配set類型的值,不允許重複

<map>

裝配map類型的值,名稱和值可以是任意類型

<props>

裝配properties類型的值,名稱和值必須是String類型

裝配ListSetArray

<bean id=mybean   class=com.model.MyBean>

<property name=objectList>

<list>

<ref  bean=object1/>

<ref  bean=object2/>

</list>

</property>

</bean>

list元素包含一個或多個值。這裏的<ref>元素用來定義spring上下文中的其他bean引用,當然還可以使用其他的元素作爲<list>成員,包括<bean><value><null/>。實際上,<list>可以包含另一個<list>作爲其成員,形成多維列表。

裝配map

<bean id=mybean  class=com.model.MyBean>

<property  name=objectMap>

<map>

<entry key =key1  value-ref=value1 />

<entry  key=key2 value-ref =value2/>

</map>

</property>

</bean>

<map>元素聲明瞭一個java.util.Map類型的值。每個<entry>元素定義了一個map成員。key屬性指定了entry的鍵,value-ref屬性定義了entry的值,並引用了spring上下文中的其他bean

屬性

用途

key

指定mapentry的鍵爲String

key-ref

指定mapentry的鍵爲spring上下文其他bean的引用

value

指定mapentry的值爲String

value-ref

指定mapentry的值爲spring上下文其他bean的引用

6. 裝配空值

爲屬性設置null值,只需要使用<null/>元素

三、 使用表達式裝配 2015-07-21

Spring3引入了Spring表達式語言 SpEL。它通過運行期間執行的表達式將值裝配到bean的屬性或構造函數參數中。

SpEL特性:

使用beanID來引用bean

調用方法和訪問對象的屬性

對值進行算術、關係和邏輯運算

正則表達式匹配

集合操作

一、 字面值

最簡單的SpEL表達式僅包含一個字面值。

<property name=count  value=#{5}/>

#{ }標記會提示Spring這個標記裏的內容是SpEL表達式,它們還可以與非SpEL表達式的值混用。

<property name=message  value=the value is #{5} />

String類型的字面值可以使用單引號或雙引號作爲字符串的界定符。例如

<property name=name  value=#{  kom  }>

二、 引用beanproperties方法

SpEL表達式能做的另一個基本失去是通過id引用其他bean

<property name=object  value=#{mybean} />

注意,是使用的value而不是ref

SpEL可以引用其他對象中的屬性。例如

<bean id=bean1  class=com.model.MyBean>

<property name=anotherbean>

<bean class=com.model.AnotherBean/>

</property>

</bean>

 

<bean id=bean2  class=com.model.MyBean>

<property  name=anotherbean  value=#{bean1.anotherbean}/>

</bean>

 

其中bean2中的屬性anotherbean引用了bean1中的anotherbean

SpEL不僅能調用bean的屬性,還可以調用它的方法。例如

<property  name=anotherbean  value=bean1.getAnotherBean() />

如果bean1null,則SpEL則會拋出一個空指針異常。可以使用null-safe存取器,使用 ?.運算符代替 來訪問方法。在放分右邊方法之前,該運算符會確保左邊項的值不會爲null。如果左邊爲null,則SpEL不會嘗試調用右邊的方法。

三、 操作類

SpEL中,使用T()運算符會調用類作用域的方法和常量。例如在SpEL中使用javaMath類,可以這樣寫:

T(java.lang.Math)

在上面的例子中,T()運算符會返回一個java.lang.Math的類對象。通過該運算符可以訪問指定類的靜態方法和常量。

<property name=randomNumber  value=#{T(java.lang.Math).random()} />

上例中調用了Math.random();

四、 SpEl值上執行操作

SpEL提供了幾種運算符,這些運算符可以用在SpEL表達式中的值上。

運算符類型

運算符

算術運算

+-*/%^

關係運算

<>==<=>=ltgteqlege

邏輯運算

andnotor、!

條件運算

?:(ternary)?:(Elvis)

正則表達式

mathes

SpEL提供了所有java支持的基礎算術運算符,它還增加了^運算符執行乘方運算。

<property  name=age  value=#{Tom.age+20} /> 

比較值

例如,比較倆個值是否相同返回boolean類型的值

<property name=equal   value=#{bean1.age==23} />

 

邏輯表達式

<property  name=sex  value=#{!  true} />

 

五、 篩選集合

可以使用SpEL引用集合中的某個成員,SpEL同樣具有基於屬性值來過濾集合成員的能力。SpEL可以從集合的成員中提取某些屬性放到一個新的集合中。

爲了展示用戶,定義一個City類。

package com.model

public class City{

private String name;

private int population;

public void setName(String name)

.

.

}

xml文件中,配置信息如下

<util : list id=cities >

<bean class=com.model.City  p:name=BeiJing  p:population=20000000/>

<bean class=com.model.City  p:name=ShangHai p:population=30000000/>

<bean class=com.model.City  p:name=HangZhou p:population=10000000 />

</util:list>

 

訪問集合成員

從集合中提取一個成員,並將它裝配到某個屬性中

<property  name=city  value=# { cities [ 2 ] } />

查詢集合成員

如果我們想從cities中查詢人口大於1500w的城市,在SpEL中,只需要使用查詢運算符 . ? [ ] 就可以做到。

<property name=bigCities  value=#{cities.?[population gt 15000000]} />

查詢運算符會創建一個新集合,新集合中只存放符合括號內的表達式的成員。

SpEL提供兩種其他查詢運算符: . ^[ ]和 . $ [ ] ,從集合中查詢出第一個匹配項和最後一個匹配項。

投影集合

 集合投影是從集合的每一個成員中選擇特定的屬性放入一個新的集合中。SpEL的投影運算符 . ! [ ] 可以做到。

假設僅需要包含城市名字的集合,

<property  name=cityName  value=#{cities.![name]} />

可以對集合進行查詢和投影運算,這裏把符合條件的大城市名字注入cityNames

<property  name=cityNames  value=#{cities.?[population gt 15000000].![name] } />

第二章 最小化Spring XML配置

Spring提供了幾種技巧,可以幫助減少XML的配置數量。

自動裝配(autowiring),有助於減少甚至消除配置<property >元素和<constructor-arg>元素,讓spring自動識別如何裝配bean的依賴關係。

自動檢測(autodiscovery)比自動裝配更進了一步,讓spring自動識別哪些類需要被配置成spring bean,從而減少對<bean> 元素的使用。

一、 自動裝配Bean屬性

一、 4種類型的自動裝配

byName   把與bean的屬性具有相同名字(或者id)的其他bean自動裝配到bean的對應屬性中。如果沒有跟屬性的名字匹配的bean,則該屬性不進行裝配。

byType    把與Bean的屬性具有相同類型的其他bean自動裝配到bean的對應屬性中。如果沒有跟屬性的類型匹配的bean,則該屬性不進行裝配。

constructor  把與bean的構造方法入參具有相同類型的其他bean自動裝配到bean的構造方法對應的入參中。

autodetect   首先嚐試使用constructor進行自動裝配,如果失敗,再嘗試使用byType進行自動裝配。

 

byName自動裝配

 

手動裝配:

<bean id=”bean class=com.model.Bean />

<bean id=bean2  class=com.model.Bean >

<property  name=name  value= Tom / >

<property  name=bean ref=bean />

</bean>

自動裝配:

<bean id=”bean class=com.model.Bean />

<bean id=bean2  class=com.model.Bean  autowire=byName>

<property  name=name  value= Tom / >

</bean>

這樣,bean2中的bean屬性就被自動裝配了。

byName自動裝配遵循一項約定:爲屬性自動裝配ID與該屬性的名字相同的Bean。使用byName自動裝配的缺點是需要假設bean的名字與其他bean的屬性的名字一樣。

byType自動裝配

當使用byType自動裝配時,spring會尋找哪一個bean的類型與屬性的類型相匹配。但byType自動裝配存在一個侷限性,如果spring尋到到多個bean,它們的類型與需要自動裝配的屬性的類型都匹配,則spring會拋出異常。所有,應用只允許存在一個bean與需要自動裝配的屬性類型相匹配。

爲了避免使用byType自動裝配帶來的歧義,spring提供2種選擇:可以爲自動裝配標識一個首選bean,或者可以取消某個bean自動裝配的候選資格。

爲自動裝配標識一個首選bean,可以使用<bean>元素的primary屬性。如果只有一個候選beanprimary屬性爲true,那麼該bean比其他候選bean優先被選擇。但是primary 默認設置爲true

如果在自動裝配時,我們希望排除某些bean,則可以設置這些beanautowire-candidate屬性爲false,這裏我們要求spring在自動裝配時忽略bean作爲候選bean

constructor自動裝配

如果要通過構造方法注入來配置bean,可以移除<constructor-arg>元素,由spring在應用上下文自動選擇bean注入到構造方法入參中。

<bean  id=bean1  class=com.model.Bean  autowire=constructor />

由於constructor自動裝配和byType自動裝配都是通過bean的類型自動裝配的,當發現多個匹配bean時,spring會拋出異常。

最佳自動裝配

我們可以設置autowire屬性爲autodetect,由spring決定。spring首先嚐試使用constructor自動裝配,如果沒有發現與構造方法匹配的bean時,spring將嘗試使用byType自動裝配。

二、 默認自動裝配

如果需要爲srping應用上下文中的每一個(或者其中大多數)bean配置相同的autowire屬性,可以在根元素<beans> 上增加一個default-autowire屬性。默認情況下,defau-autowire屬性被設置爲none

三、 混合使用自動裝配和顯示裝配

對某個bean選擇了自動裝配策略,不代表不能對該bean的某些屬性進行顯示裝配。

注意,使用constructor自動裝配時,必須讓spring自動裝配構造方法的所有入參,不能混合使用constructor自動裝配策略。

二、 使用註解裝配

spring2.25開始,spring支持使用註解自動裝配bean的屬性。

spring容器默認禁止註解裝配。使用前需要啓用:

<beans>元素中配置<context:annotation-config />,如下

<beans>

……………….

<context:annotation-config />

</beans>

1. 使用@Autowired

使用@Autowiredspring自動裝配Beancity屬性,則可以對setCity()方法進行標註,如下

@Autowired

public void setCity(City city){

this.city=city;

}

現在我們可以移除city屬性對應的<property>元素了,Spring會嘗試對該方法執行byType自動裝配。

我們不僅可以使用它標註setter方法,還可以標註需要自動 裝配bean引用的任意方法。@Autowired註解可以標註構造方法。

另外當用@Autowired直接標註屬性,並刪除setter方法,

@Autowired

private City city;

@Autowored甚至不會受限於private關鍵字。

如果沒有匹配的bean或者存在多個匹配的bean@Autowired註解就會遇到一些麻煩。但是這兩種情況都有相應的解決辦法。如下

2. 可選的自動裝配

屬性不一定非要裝配,null也是可以接受的。在這種情況下,可以設置@Autowiredrequired屬性爲false來配置自動裝配是可選的。這樣,spring將先嚐試裝配,如果找不到與之匹配的bean,應用不會發生任何問題,而屬性值會被設置爲null

3. 限定歧義性的依賴

當與之匹配的bean有多個的時候,可以使用@Qualifier註解來指明使用id來匹配bean,例如

@Autowired

@Qualifier(ShangHai)

private City city;

如上,@Qualifier註解將嘗試注入idShangHai 的bean

4. 在註解注入中使用表達式

spring3.0引入了@Value,可以讓我們使用註解裝配String類型的值和基本類型的值,例如intboolean。例如

@Value(Tom Clone)

private String name;

在這裏,爲String類型的屬性name裝配了一個String類型的值。

藉助於SpEL表達式,使得@Value成爲強大的裝配可選方案。

@Value(#{city[0].name})

private String name;

5. @Scope

 

相當於<bean>元素中的scope屬性

6. @postconstruct

相當於init-method

7. @predestor

相當於destory-method

三、 自動檢測bean

<context:component-scan>元素除了完成與<context:annotation-config>一樣的工作,還允許spring自動檢測bean和定義bean。這意味着不用<bean>元素,spring中大多數bean能偶實現定義和裝配。

爲了完成spring自動檢測,需要使用 <context:component-scan>代替<context:annotation-config>

<beans>

…………………………………………….

<context:component-scan  base-package=com.model>

</ context:component-scan >

</beans>

 

<context:component-scan>元素會自動掃描指定的包及其所有子包,並查找出能自動註冊爲bean的類。base-package屬性標識了所掃描的包。

1. 爲自動檢測標註bean

默認情況下,<context:component-scan>查找使用構造型(stereotype)註解所標註的類,這些特殊的註解如下

@Component   通用的構造型註解,標識該類爲spring組件

@Controller  標識將該類定義爲spring mvc controller

@Repository   標識將該類定義爲數據倉庫

@Service  標識將該類定義爲服務

使用@Component 標註的任意自定義註解

可以使用 @Component( id )在括號裏顯式的指定beanid

2. 過濾組件掃描

在如何掃描來獲得候選bean方面,<context:component-scan>非常靈活。通過<context:component-scan>配置<context:include-filter>或者<context:exclude-filter>子元素,可以隨意調整掃描行爲。


 

<context:include-filter>typeexpression屬性一起寫作來定義組件掃描策略。

過濾器類型

描述

annotation

過濾器掃描使用指定註解標註的那些類,通過expression屬性指定要掃描的註解

assignable

過濾器掃描派生於expression屬性所指定類型的那些類

 

aspectj

過濾器掃描與expression屬性所指定的AspectJ表達式所匹配的那些類

custom

使用自定義的org.springframework.core.type.TypeFilter實現類,該類由expression屬性指定

regex

過濾器掃描類的名稱與expression屬性所指定的正則表達式所匹配的類

除了使用<context:include-filter>告知哪些類需要註冊爲bean以外,還可以使用<context:exclude-filter>告知哪些類不需要註冊爲bean

四、 使用基於Spring基於java的配置

 

第三章 面向切面的Spring

一、 什麼是面向切面編程(AOP)

1. 定義AOP術語

描述切面常用的術語有通知(advice)、切點(pointcut)和連接點(join point)

通知(advice)

AOP術語中,切面的工作被稱之爲通知。通知定義了切面是什麼以及何時使用。除了描述切面要完成的工作,通知還解決了何時執行這個工作的問題。它應該應用於某個方法被調用之前?之後?之前和之後?還是隻在方法拋出異常時?

spring切面可以應用5種類型的通知

Before  在方法被調用之前調用通知

After   在方法完成之後調用通知,無論方法執行是否成功

After-returning  在方法成功執行之後調用通知

After-throwing 在方法拋出異常後調用通知

Around  通知包裹了被通知的方法,被通知的方法調用之前和調用之後執行自定義的行爲。

連接點(Join point

連接點是在應用執行過程中能夠插入切面的一個點。這個店可以是調用方法時、拋出異常時、甚至修改一個字段時。切面代碼可以利用這些點插入到應用的正常流程之中,並添加新的行爲。

切點(pointcut

一個切面並不需要通知應用的所有連接點。切點有助於縮小切面所通知連接點的範圍。

切面(Aspect

切面是通知和切點的結合。通知和切點共同定義了關於切面的全部內容-它是什麼,在何時和何處完成其功能。

引用(Introduction

引用允許我們向現有的類添加新的方法或屬性。

織入(Weaving

織入是將切面應用到目標對象來創建新的代理對象的過程。切面在指定的連接點被織入到目標對象中。

2. 五種類型的通知

Before 在方法被調用之前調用通知

After 在方法完成之後調用通知,無論方法是否執行成功

After-returnning 在方法成功執行之後調用通知

After-throwing在方法拋出異常後調用通知

Around 通知包裹了被通知的方法,被通知的方法調用之前和調用之後執行自定義的行爲。

3. 編寫切點(annotation方式)

首先,需要在xml文件中打開aop,在xml文件中添加以下代碼

<aop:aspectj-autoproxy/>

添加aspectJ的依賴包aspectjweaver.jar

在切面類上使用註解@Aspect,並且使用註解@Component或者xml文件配置方式把切面類配置成bean

使用execution()指示器選擇Instrumentplay()方法。方法表達式以*號開始,標識了不需要關心方法返回值的類型,然後我們置頂了全限定類名和方法名。對於方法參數列表,使用( . . )標識切點選擇任意的play()方法,無論該方法的入參是什麼。


 

現在假設我們需要配置切點僅匹配com.springinaction.springidol包。此時可以使用withdin()指示器來限制匹配。如下

execution(*com.springincation.springidol.Instrument.play(..))&&within(com.springincation.springidol.*)

注意,使用&&execution()within()指示器連接在一起形成and關係。類似,也可以使用||!操作符,在xml文件中,&符號具有特殊意義,所以使用and代替&&。同樣可以使用ornot

注意,bean()指示器允許我們在切點表達式中使用bean id來標識beanbean()指示器使用bean  idbean名稱作爲參數來限制切點只匹配特定的bean。 

4. xml中聲明切面

AOP配置元素

描述

<aop:advisor>

定義AOP通知

<aop:after>

定義AOP後置通知(不管通知的方法是否執行成功)

<aop:after-returning>

定義AOP after-returning通知

<aop:around>

定義AOP around 通知

<aop:aspect>

定義切面

<aop:aspectj-autoproxy>

啓用@AspectJ註解

<aop:before>

定義AOP after通知

<aop:declare-parents>

爲被通知的對象引入額外的接口,並透明地實現

<aop:pointcut>

定義切點

<aop:config>

頂層的AOP元素,大多數<aop:*>元素必須包含在此元素下


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