天天看點

Spring2.5注釋驅動與基于注釋的MVC

寫在前面:

好長時間沒有寫部落格了,主要是最近一直忙于工作上面的事情沒有研究什麼新的東西,也沒有什麼寫的,最近應一個朋友的邀請一起開發一套教材,我才有開始對Spring研究起來,今天把寫的其中一部分貼出來與大家共享.如有不足之處請多多指教.

Spring2.5注釋驅動

       <b>8.4.1</b><b> Spring2.5</b><b>注釋驅動</b>

       注釋文法越來越多的被業界所使用,并且注釋配置相對于 XML 配置具有很多的優勢:它可以充分利用 Java 的反射機制擷取類結構資訊,這些資訊可以有效減少配置的工作。注釋和 Java 代碼位于一個檔案中,而 XML 配置采用獨立的配置檔案,大多數配置資訊在程式開發完成後都不會調整,如果配置資訊和 Java 代碼放在一起,有助于增強程式的内聚性。而采用獨立的 XML 配置檔案,程式員在編寫一個功能時,往往需要在程式檔案和配置檔案中不停切換,這種思維上的不連貫會降低開發效率。是以在很多情況下,注釋配置比 XML 配置更受歡迎,注釋配置有進一步流行的趨勢。Spring 2.5 的一大增強就是引入了很多注釋類,現在您已經可以使用注釋配置完成大部分XML 配置的功能。

       在使用注釋配置之前,先來回顧一下傳統上是如何配置 Bean 并完成 Bean 之間依賴關系的建立。

代碼清單1  Foo.java Foo對象有一個String類型的name屬性.

              <b>package</b> com.tony.test;

<b>public</b> <b>class</b> Foo {

        <b>private</b> String name;

            <b>public</b> String toStirng(){

               <b>return</b> "Foo Name is :" + <b>this</b>.name;

            }

<b>Set</b><b>和</b><b>get</b><b>方法</b>

}

代碼清單2  Bar.java Bar對象有一個String類型的add屬性.

<b>package</b> com.tony.test;

<b>public</b> <b>class</b> Bar {

        <b>private</b> String add;

               <b>return</b> "Bar Add is :" + <b>this</b>.add;

代碼清單3 Main.java Main對象有兩個屬性分别是Foo和Bar

<b>public</b> <b>class</b> Main {

        <b>private</b> Foo foo;

        <b>private</b> Bar bar;

            <b>public</b> String toString(){

<b>return</b> "Main : [" + <b>this</b>.foo.toStirng() +" "+ <b>this</b>.bar.toStirng() + "]";

代碼清單4 配置檔案spring-config-beans.xml

        &lt;bean id="main" class="com.tony.test.Main"&gt;

           &lt;property name="foo" ref="foo"&gt;&lt;/property&gt;

           &lt;property name="bar" ref="bar"&gt;&lt;/property&gt;

        &lt;/bean&gt;

        &lt;bean id="foo" class="com.tony.test.Foo"&gt;

           &lt;property name="name" value="Foo"&gt;&lt;/property&gt;

        &lt;bean id="bar" class="com.tony.test.Bar"&gt;

           &lt;property name="add" value="Bar"&gt;&lt;/property&gt;

&lt;/bean&gt;

代碼清單 5 Test.java Test類用于初始化Spring容器并獲得main對象

<b>import</b> org.springframework.context.ApplicationContext;

<b>import</b> org.springframework.context.support.

ClassPathXmlApplicationContext;

<b>public</b> <b>class</b> Test {

            <b>public</b> <b>static</b> <b>void</b> main(String[] args) {   

                 String[] locations = {"spring-config-beans.xml"};   

ApplicationContext ctx = <b>new</b> ClassPathXmlApplicationContext(locations);   

                 Main main = (Main) ctx.getBean("main");   

                 System.out.println(main);   

            }  

運作Test類控制台輸出以下資訊:

Main : [Foo Name is :Foo Bar Add is :Bar]

這說明Spring已經完成了Bean的建立和裝配工作。

<b>1)</b><b>使用 @Autowired </b><b>注釋</b>

Spring 2.5 引入了 @Autowired 注釋,它可以對類成員變量、方法及構造函數進行标注,完成自動裝配的工作。下面我們來看一下使用 @Autowired 進行成員變量自動注入的代碼:

代碼清單6使用 @Autowired 注釋的 Main.java,此時可以将Main.java類中的set和get方法删除

<b>import</b> org.springframework.beans.factory.annotation.Autowired;

           @Autowired

           <b>private</b> Foo foo;

           <b>private</b> Bar bar;

           <b>public</b> String toString(){

           }

Spring 通過一個 BeanPostProcessor 對 @Autowired 進行解析,是以要讓 @Autowired 起作用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean

代碼清單 7 修改配置檔案

&lt;!-- 該 BeanPostProcessor 将自動對标注 @Autowired 的 Bean 進行注入 --&gt;   

&lt;bean class="org.springframework.beans.factory.annotation.

AutowiredAnnotationBeanPostProcessor"/&gt;

        &lt;!—此時移除 main Bean 的屬性注入資訊 --&gt;  

        &lt;bean id="main" class="com.tony.test.Main"&gt;&lt;/bean&gt;

當 Spring 容器啟動時,AutowiredAnnotationBeanPostProcessor 将掃描 Spring 容器中所有 Bean,當發現 Bean 中擁有 @Autowired 注釋時就找到和其比對(預設按類型比對)的 Bean,并将其注入。

<b>2)</b><b>使用@Qualifier </b><b>注釋</b>

Spring 允許我們通過 @Qualifier 注釋指定注入 Bean 的名稱,這樣就不會産生注入錯誤了,請看下面代碼清單:

       代碼清單8 修改Main.java類中的foo屬性注釋增加注釋@Qualifier("foo1")

           @Qualifier("foo1")

代碼清單9 在配置檔案中增加id為foo2 Bean定義

        &lt;bean id="foo1" class="com.tony.test.Foo"&gt;

           &lt;property name="name" value="Foo1"&gt;&lt;/property&gt;

        &lt;bean id="foo2" class="com.tony.test.Foo"&gt;

           &lt;property name="name" value="Foo2"&gt;&lt;/property&gt;

運作Test.java控制台輸出如下資訊:

Main : [Foo Name is :Foo1 Bar Add is :Bar]

證明Spring容器成功将foo1注入進main類中

<b>3)</b><b>使用 </b><b>&lt;context:annotation-config/&gt; </b><b>簡化配置</b>

Spring 2.1 添加了一個新的 context 的 Schema 命名空間,該命名空間對注釋驅動、屬性檔案引入、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會做任何事情的,它僅提供中繼資料資訊。要使中繼資料資訊真正起作用,必須讓負責處理這些中繼資料的處理器工作起來。而我們前面所介紹的 AutowiredAnnotationBeanPostProcessor 就是處理這些注釋中繼資料的處理器。但是直接在 Spring 配置檔案中定義這些 Bean 顯得比較笨拙。Spring 為我們提供了一種友善的注冊這些 BeanPostProcessor 的方式,這就是 &lt;context:annotation-config/&gt;。請看下面的代碼清單:

代碼清單10

&lt;context:annotation-config/&gt;

代碼清單中将

替換成為&lt;context:annotation-config/&gt;

&lt;context:annotationconfig/&gt; 将隐式地向 Spring 容器注冊 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor 這 4 個 BeanPostProcessor。

<b>4) </b><b>使用 @Component</b>

雖然我們可以通過 @Autowired在 Bean 類中使用自動注入功能,但是 Bean 還是在 XML 檔案中通過 &lt;bean&gt; 進行定義,也就是說,在 XML 配置檔案中定義 Bean,通過 @Autowired 為 Bean 的成員變量、方法入參或構造函數入參提供自動注入的功能。能否也通過注釋定義 Bean,從 XML 配置檔案中完全移除 Bean 定義的配置呢?答案是肯定的,我們通過 Spring 2.5 提供的 @Component 注釋就可以達到這個目标。請看下面的代碼清單:

代碼清單11 Foo.java

@Component

           <b>private</b> String name = "Foo's name.";

           <b>public</b> String toStirng(){

              <b>return</b> "Foo Name is :" + <b>this</b>.name;

在類的開始位置使用@Component注釋,标明此類是一個Bean

代碼清單12 Main.java

@Component("main")

    <b>private</b> Bar bar;

<b>……</b>

@Component 有一個可選的入參,用于指定 Bean 的名稱,在 Main 中,我們就将 Bean 名稱定義為“main”。在使用 @Component 注釋後,Spring 容器必須啟用類掃描機制以啟用注釋驅動 Bean 定義和注釋驅動 Bean 的自動注入的政策。Spring 2.5 對 context 命名空間進行了擴充,提供了這一功能。

代碼清單13 Spring配置檔案中隻保留以下配置資訊

&lt;context:component-scan base-package="com.tony.test"/&gt;

這裡,所有通過 &lt;bean&gt; 元素定義 Bean 的配置内容已經被移除,僅需要添加一行 &lt;context:component-scan/&gt; 配置就解決所有問題了——Spring XML 配置檔案得到了極緻的簡化(當然配置中繼資料還是需要的,隻不過以注釋形式存在罷了)。&lt;context:component-scan/&gt; 的 base-package 屬性指定了需要掃描的類包,類包及其遞歸子包中所有的類都會被處理。

       <b>8.4.2</b><b> Spring2.5</b><b>基于注解驅動的MVC</b>

Spring 2.5 也為 Spring MVC 引入了注釋驅動功能。現在我們無須讓 Controller 繼承任何接口,無需在 XML配置檔案中定義請求和 Controller 的映射關系,僅僅使用注釋就可以讓一個 POJO 具有 Controller 的絕大部分功能 —— Spring MVC 架構的易用性得到了進一步的增強。

由于 Spring MVC 的 Controller 必須事先是一個 Bean,是以 @Controller 注解是不可缺少的。請看下面的代碼清單

代碼清單1

              @Controller //将這個類标注為Controller

<b>public</b> <b>class</b> FooController {

            @Autowired

            <b>private</b> FooService fooService;

            @RequestMapping("/list.do") //URL請求映射

            <b>public</b> String[] list() {

            String[] list = fooService.getAll();

             System.out.println(list);

             <b>return</b> list;

            @RequestMapping("/del.do") //URL請求映射

<b>public</b> <b>void</b> del(HttpServletRequest request, HttpServletResponse response) {

                fooService.doDel(request.getParameter("id"));

在代碼清單1中我們通過@Controller注釋将FooController.java 标注為一個控制器,而不需繼承或者實作任何類和接口,就使FooController.java擁有了控制器的功能。代碼清單1中使用了兩個連結分别通路了不同的方法,在實際應用中我們也許有另外一種需求一個控制器隻接受一個URL請求,而控制器中不同的方法來處理URL請求中攜帶的不同的參數,請看下面的代碼清單。

<b>2)  </b><b>一個</b><b> </b><b>Controller</b><b> </b><b>對應一個</b><b> </b><b>URL</b><b>,由請求參數決定請求處理方法</b><b></b>

代碼清單2

@Controller

@RequestMapping("/doFoo.do")// 指定控制器對應URL請求

           <b>private</b> FooService fooService;

           //list方法對應URL /doFoo.do?mode=list

           @RequestMapping(params = "mode=list")

               String[] list = fooService.getAll();

                System.out.println(list);

                <b>return</b> list;

           //del方法對應URL /doFoo.do?mode=del

           @RequestMapping(params = "mode=del")

<b>public</b> <b>void</b> del(HttpServletRequest request,

HttpServletResponse response) {

               fooService.doDel(request.getParameter("id"));

代碼清單2中滿足了針對不同粒度程式設計的需要。我們還可以讓請求處理方法處理特定的 HTTP 請求如POST類型的,請看下面的代碼清單。

<b>3)  </b><b>讓請求處理方法處理特定的</b><b> HTTP </b><b>請求方法</b><b></b>

代碼清單3

           //隻針對POST請求

        @RequestMapping(params = "mode=submit",

method = RequestMethod.POST)

           <b>public</b> String submit(HttpServletRequest request,

               HttpServletResponse response){

              System.out.println("調用 submit 方法.");

              <b>return</b> "success";

方法submit隻處理類型為POST的URL請求

代碼清單4

           //del方法對應URL /doFoo.do?mode=del&amp;id=10

            <b>public</b> String del(<b>int</b> id) {

               fooService.doDel(id);

               <b>return</b> "success";

當我們發送 /doFoo.do?mode=del&amp;id=10 的 URL 請求時,

Spring 不但讓 del() 方法處理這個請求,而且還将 id 請求參數在類型轉換後綁定到 del() 方法的 id 入參上。而 del() 方法的傳回類型是 String,它将被解析為邏輯視圖的名稱。也就是說 Spring 在如何給處理方法入參自動指派以及如何将處理方法傳回值轉化為ModelAndView 中的過程中存在一套潛在的規則,不熟悉這個規則就不可能很好地開發基于注解的請求處理方法,是以了解這個潛在規則無疑成為了解 Spring MVC 架構基于注解功能的核心問題。代碼清單4還可以寫成下面這種形式

代碼清單5

            <b>public</b> String del(@RequestParam("id")<b>int</b> id) {

代碼清單5中對 del() 請求處理方法的 id 入參标注了 @RequestParam("id") 注釋,是以它将和 id 的 URL 參數綁定。

我的其它Spring文章,也許會對您有幫助

<a href="http://tonyaction.blog.51cto.com/227462/84008" target="_blank">Spring的任務排程和郵件發送</a>

<a href="http://tonyaction.blog.51cto.com/227462/84178" target="_blank">Spring應用的單元測試</a>

<a href="http://tonyaction.blog.51cto.com/227462/84724" target="_blank">Spring的資料庫支援</a>

<a href="http://tonyaction.blog.51cto.com/227462/84893" target="_blank">Spring的MVC架構</a>

<a href="http://tonyaction.blog.51cto.com/227462/85159" target="_blank">Spring的IoC容器</a>

<a href="http://tonyaction.blog.51cto.com/227462/85504" target="_blank">Spring對AOP的支援</a>

<a href="http://tonyaction.blog.51cto.com/227462/83874" target="_blank">Spring2.5注釋驅動與基于注釋的MVC</a>

本文轉自 tony_action 51CTO部落格,原文連結:http://blog.51cto.com/tonyaction/83874,如需轉載請自行聯系原作者