spring mvc系列文章 - Spring MVC注释驱动

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 ;
            }
Setget方法
}
代码清单 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 ;
            }
Setget方法
}
代码清单 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() +  "]" ;
            }
Setget方法
}
代码清单 配置文件 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类中的setget方法删除
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 修改配置文件
<!--  BeanPostProcessor 将自动对标注 @Autowired  Bean 进行注入 -->    
< bean  class = "org.springframework.beans.factory.annotation.
AutowiredAnnotationBeanPostProcessor" />
         <!—此时移除 main Bean 的属性注入信息 -->  
         < 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 的名称,这样就不会产生注入错误了,请看下面代码清单:
       代码清单修改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() +  "]" ;
           }
}
代码清单在配置文件中增加idfoo2 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 容器注册AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessor 以及 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  参数绑定。



 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值