寫在前面:
好長時間沒有寫博客了,主要是最近一直忙於工做上面的事情沒有研究什麼新的東西,也沒有什麼寫的,最近應一個朋友的邀請一塊兒開發一套教材,我纔有開始對Spring研究起來,今天把寫的其中一部分貼出來與你們共享.若有不足之處請多多指教.
Spring2.5註釋驅動
8.4.1
Spring2.5註釋驅動
註釋語法愈來愈多的被業界所使用,而且註釋配置相對於 XML 配置具備不少的優點:它能夠充分利用 Java 的反射機制獲取類結構信息,這些信息能夠有效減小配置的工做。註釋和 Java 代碼位於一個文件中,而 XML 配置採用獨立的配置文件,大多數配置信息在程序開發完成後都不會調整,若是配置信息和 Java 代碼放在一塊兒,有助於加強程序的內聚性。而採用獨立的 XML 配置文件,程序員在編寫一個功能時,每每須要在程序文件和配置文件中不停切換,這種思惟上的不連貫會下降開發效率。所以在不少狀況下,註釋配置比 XML 配置更受歡迎,註釋配置有進一步流行的趨勢。Spring 2.5 的一大加強就是引入了不少註釋類,如今您已經可使用註釋配置完成大部分 XML 配置的功能。
在使用註釋配置以前,先來回顧一下傳統上是如何配置 Bean 並完成 Bean 之間依賴關係的創建。
代碼清單1
Foo.java Foo
對象有一個
String
類型的
name
屬性
.
package
com.tony.test;
public
class
Foo {
private
String
name
;
public
String toStirng(){
return
"Foo Name is :"
+
this
.
name
;
}
Set
和
get
方法
}
代碼清單
2 Bar.java Bar
對象有一個
String
類型的
add
屬性
.
package
com.tony.test;
public
class
Bar {
private
String
add
;
public
String toStirng(){
return
"Bar Add is :"
+
this
.
add
;
}
Set
和
get
方法
}
代碼清單
3 Main.java Main
對象有兩個屬性分別是
Foo
和
Bar
package
com.tony.test;
public
class
Main
{
private
Foo
foo
;
private
Bar
bar
;
public
String toString(){
return
"Main : ["
+
this
.
foo
.toStirng() +
" "
+
this
.
bar
.toStirng() +
"]"
;
}
Set
和
get
方法
}
代碼清單
4
配置文件
spring-config-beans.xml
<
bean
id
=
"main"
class
=
"com.tony.test.Main"
>
<
property
name
=
"foo"
ref
=
"foo"
></
property
>
<
property
name
=
"bar"
ref
=
"bar"
></
property
>
</
bean
>
<
bean
id
=
"foo"
class
=
"com.tony.test.Foo"
>
<
property
name
=
"name"
value
=
"Foo"
></
property
>
</
bean
>
<
bean
id
=
"bar"
class
=
"com.tony.test.Bar"
>
<
property
name
=
"add"
value
=
"Bar"
></
property
>
</
bean
>
代碼清單
5 Test.java Test
類用於初始化
Spring
容器並得到
main
對象
package
com.tony.test;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.support.
ClassPathXmlApplicationContext
;
public
class
Test {
public
static
void
main(String[] args) {
String[] locations = {
"spring-config-beans.xml"
};
ApplicationContext ctx =
new
ClassPathXmlApplicationContext(locations);
Main main = (Main) ctx.getBean(
"main"
);
System.
out
.println(main);
}
}
運行
Test
類控制檯輸出如下信息:
Main : [Foo Name is :Foo Bar Add is :Bar]
這說明Spring已經完成了Bean的建立和裝配工做。
1)使用 @Autowired 註釋
Spring 2.5 引入了 @Autowired 註釋,它能夠對類成員變量、方法及構造函數進行標註,完成自動裝配的工做。下面咱們來看一下使用 @Autowired 進行成員變量自動注入的代碼:
代碼清單6使用 @Autowired 註釋的 Main.java,此時能夠將Main.java類中的set和get方法刪除
package
com.tony.test;
import
org.springframework.beans.factory.annotation.Autowired;
public
class
Main
{
@Autowired
private
Foo
foo
;
@Autowired
private
Bar
bar
;
public
String toString(){
return
"Main : ["
+
this
.
foo
.toStirng() +
" "
+
this
.
bar
.toStirng() +
"]"
;
}
}
Spring 經過一個 BeanPostProcessor 對 @Autowired 進行解析,因此要讓 @Autowired 起做用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean
代碼清單 7 修改配置文件
<
bean
class
=
"org.springframework.beans.factory.annotation.
AutowiredAnnotationBeanPostProcessor"
/>
<
bean
id
=
"main"
class
=
"com.tony.test.Main"
></
bean
>
<
bean
id
=
"foo"
class
=
"com.tony.test.Foo"
>
<
property
name
=
"name"
value
=
"Foo"
></
property
>
</
bean
>
<
bean
id
=
"bar"
class
=
"com.tony.test.Bar"
>
<
property
name
=
"add"
value
=
"Bar"
></
property
>
</
bean
>
當 Spring 容器啓動時,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中全部 Bean,當發現 Bean 中擁有 @Autowired 註釋時就找到和其匹配(默認按類型匹配)的 Bean,並將其注入。
2)使用@Qualifier 註釋
Spring 容許咱們經過 @Qualifier 註釋指定注入 Bean 的名稱,這樣就不會產生注入錯誤了,請看下面代碼清單:
代碼清單8 修改Main.java類中的foo屬性註釋增長註釋
@Qualifier
(
"foo1"
)
public
class
Main
{
@Autowired
@Qualifier
(
"foo1"
)
private
Foo
foo
;
@Autowired
private
Bar
bar
;
public
String toString(){
return
"Main : ["
+
this
.
foo
.toStirng() +
" "
+
this
.
bar
.toStirng() +
"]"
;
}
}
代碼清單9 在配置文件中增長id爲foo2 Bean定義
<
bean
class
=
"org.springframework.beans.factory.annotation.
AutowiredAnnotationBeanPostProcessor"
/>
<
bean
id
=
"main"
class
=
"com.tony.test.Main"
></
bean
>
<
bean
id
=
"foo1"
class
=
"com.tony.test.Foo"
>
<
property
name
=
"name"
value
=
"Foo1"
></
property
>
</
bean
>
<
bean
id
=
"foo2"
class
=
"com.tony.test.Foo"
>
<
property
name
=
"name"
value
=
"Foo2"
></
property
>
</
bean
>
<
bean
id
=
"bar"
class
=
"com.tony.test.Bar"
>
<
property
name
=
"add"
value
=
"Bar"
></
property
>
</
bean
>
運行
Test.java
控制檯輸出以下信息
:
Main : [Foo Name is :Foo1 Bar Add is :Bar]
證實
Spring
容器成功將
foo1
注入進
main
類中
3)使用
<context:annotation-config/>
簡化配置
Spring 2.1 添加了一個新的 context 的 Schema 命名空間,該命名空間對註釋驅動、屬性文件引入、加載期織入等功能提供了便捷的配置。咱們知道註釋自己是不會作任何事情的,它僅提供元數據信息。要使元數據信息真正起做用,必須讓負責處理這些元數據的處理器工做起來。而咱們前面所介紹的 AutowiredAnnotationBeanPostProcessor 就是處理這些註釋元數據的處理器。可是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 爲咱們提供了一種方便的註冊這些 BeanPostProcessor 的方式,這就是
<context:annotation-config/>
。請看下面的代碼清單:
代碼清單
10
<
context:annotation-config
/>
<
bean
id
=
"main"
class
=
"com.tony.test.Main"
></
bean
>
<
bean
id
=
"foo1"
class
=
"com.tony.test.Foo"
>
<
property
name
=
"name"
value
=
"Foo1"
></
property
>
</
bean
>
<
bean
id
=
"foo2"
class
=
"com.tony.test.Foo"
>
<
property
name
=
"name"
value
=
"Foo2"
></
property
>
</
bean
>
<
bean
id
=
"bar"
class
=
"com.tony.test.Bar"
>
<
property
name
=
"add"
value
=
"Bar"
></
property
>
</
bean
>
代碼清單中將
<
bean
class
=
"org.springframework.beans.factory.annotation.
AutowiredAnnotationBeanPostProcessor"
/>
替換成爲
<
context:annotation-config
/>
<context:annotationconfig/> 將隱式地向 Spring 容器註冊 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor 這 4 個 BeanPostProcessor。
4) 使用 @Component
雖然咱們能夠經過 @Autowired在 Bean 類中使用自動注入功能,可是 Bean 仍是在 XML 文件中經過 <bean> 進行定義,也就是說,在 XML 配置文件中定義 Bean,經過 @Autowired 爲 Bean 的成員變量、方法入參或構造函數入參提供自動注入的功能。可否也經過註釋定義 Bean,從 XML 配置文件中徹底移除 Bean 定義的配置呢?答案是確定的,咱們經過 Spring 2.5 提供的 @Component 註釋就能夠達到這個目標。請看下面的代碼清單:
代碼清單11 Foo.java
@Component
public
class
Foo {
private
String
name
=
"Foo's name."
;
public
String toStirng(){
return
"Foo Name is :"
+
this
.
name
;
}
}
在類的開始位置使用
@Component
註釋
,
標明此類是一個
Bean
代碼清單
12 Main.java
@Component
(
"main"
)
public
class
Main
{
@Autowired
private
Foo
foo
;
@Autowired
private
Bar
bar
;
……
@Component 有一個可選的入參,用於指定 Bean 的名稱,在 Main 中,咱們就將 Bean 名稱定義爲「main」。在使用 @Component 註釋後,Spring 容器必須啓用類掃描機制以啓用註釋驅動 Bean 定義和註釋驅動 Bean 的自動注入的策略。Spring 2.5 對 context 命名空間進行了擴展,提供了這一功能。
代碼清單13 Spring配置文件中只保留如下配置信息
<
context:component-scan
base-package
=
"com.tony.test"
/>
這裏,全部經過 <bean> 元素定義 Bean 的配置內容已經被移除,僅須要添加一行 <context:component-scan/> 配置就解決全部問題了——Spring XML 配置文件獲得了極致的簡化(固然配置元數據仍是須要的,只不過以註釋形式存在罷了)。<context:component-scan/> 的 base-package 屬性指定了須要掃描的類包,類包及其遞歸子包中全部的類都會被處理。
8.4.2
Spring2.5基於註解驅動的MVC
Spring 2.5 也爲 Spring MVC 引入了註釋驅動功能。如今咱們無須讓 Controller 繼承任何接口,無需在 XML 配置文件中定義請求和 Controller 的映射關係,僅僅使用註釋就可讓一個 POJO 具備 Controller 的絕大部分功能 —— Spring MVC 框架的易用性獲得了進一步的加強。
因爲 Spring MVC 的 Controller 必須事先是一個 Bean,因此 @Controller 註解是不可缺乏的。請看下面的代碼清單
代碼清單1
@Controller
//
將這個類標註爲
Controller
public
class
FooController {
@Autowired
private
FooService
fooService
;
@RequestMapping
(
"/list.do"
)
//URL
請求映射
public
String[] list() {
String[] list =
fooService
.getAll();
System.
out
.println(list);
return
list;
}
@RequestMapping
(
"/del.do"
)
//URL
請求映射
public
void
del
(HttpServletRequest request, HttpServletResponse response) {
fooService
.doDel(request.getParameter(
"id"
));
}
}
在代碼清單
1
中咱們經過
@
Controller
註釋將
FooController.java
標註爲一個控制器
,
而不需繼承或者實現任何類和接口,就使
FooController.java
擁有了控制器的功能。代碼清單
1
中使用了兩個連接分別訪問了不一樣的方法,在實際應用中咱們也許有另一種需求一個控制器只接受一個
URL
請求,而控制器中不一樣的方法來處理
URL
請求中攜帶的不一樣的參數,請看下面的代碼清單。
2)
一個 Controller 對應一個 URL,由請求參數決定請求處理方法
代碼清單
2
@Controller
@RequestMapping
(
"/doFoo.do"
)
//
指定控制器對應
URL
請求
public
class
FooController {
@Autowired
private
FooService
fooService
;
//list
方法對應
URL /doFoo.do?mode=list
@RequestMapping
(params =
"mode=list"
)
public
String[] list() {
String[] list =
fooService
.getAll();
System.
out
.println(list);
return
list;
}
//del
方法對應
URL /doFoo.do?mode=
del
@RequestMapping
(params =
"mode=
del
"
)
public
void
del
(HttpServletRequest request,
HttpServletResponse response) {
fooService
.doDel(request.getParameter(
"id"
));
}
}
代碼清單2中知足了針對不一樣粒度程序設計的須要。咱們還能夠讓請求處理方法處理特定的 HTTP 請求如POST類型的,請看下面的代碼清單。
3)
讓請求處理方法處理特定的 HTTP 請求方法
代碼清單3
@Controller
@RequestMapping
(
"/doFoo.do"
)
//
指定控制器對應
URL
請求
public
class
FooController {
//
只針對
POST
請求
@RequestMapping
(params =
"mode=submit"
,
method = RequestMethod.
POST
)
public
String submit(HttpServletRequest request,
HttpServletResponse response){
System.
out
.println(
"
調用
submit
方法
."
);
return
"success"
;
}
}
方法
submit
只處理類型爲
POST
的
URL
請求
代碼清單4
@Controller
@RequestMapping
(
"/doFoo.do"
)
//
指定控制器對應
URL
請求
public
class
FooController {
@Autowired
private
FooService
fooService
;
//del
方法對應
URL /doFoo.do?mode=
del
&id=10
@RequestMapping
(params =
"mode=
del
"
)
public
String
del
(
int
id) {
fooService
.doDel(id);
return
"success"
;
}
}
當咱們發送
/doFoo.do?mode=
del
&id=10
的
URL
請求時,
Spring
不但讓
del()
方法處理這個請求,並且還將
id
請求參數在類型轉換後綁定到
del()
方法的
id
入參上。而
del()
方法的返回類型是
String
,它將被解析爲邏輯視圖的名稱。也就是說
Spring
在如何給處理方法入參自動賦值以及如何將處理方法返回值轉化爲
ModelAndView
中的過程當中存在一套潛在的規則,不熟悉這個規則就不可能很好地開發基於註解的請求處理方法,所以瞭解這個潛在規則無疑成爲理解
Spring MVC
框架基於註解功能的核心問題。代碼清單
4
還能夠寫成下面這種形式
代碼清單
5
@Controller
@RequestMapping
(
"/doFoo.do"
)
//
指定控制器對應
URL
請求
public
class
FooController {
@Autowired
private
FooService
fooService
;
//del
方法對應
URL /doFoo.do?mode=
del
&id=10
@RequestMapping
(params =
"mode=
del
"
)
public
String
del
(
@RequestParam
(
"id"
)
int
id) {
fooService
.doDel(id);
return
"success"
;
}
}
代碼清單
5
中對
del()
請求處理方法的
id
入參標註了
@RequestParam("id")
註釋,因此它將和
id
的
URL
參數綁定。