Spring2.5注释驱动与基于注释的MVC

简介:
写在前面:
好长时间没有写博客了,主要是最近一直忙于工作上面的事情没有研究什么新的东西,也没有什么写的,最近应一个朋友的邀请一起开发一套教材,我才有开始对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 方法
}
代码清单 配置文件 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  参数绑定。









本文转自 tony_action 51CTO博客,原文链接:http://blog.51cto.com/tonyaction/83874,如需转载请自行联系原作者
目录
相关文章
|
13天前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
3天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
344 5
|
1月前
|
Java 数据库连接 Spring
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
|
1月前
|
XML JSON 数据库
SpringMVC入门到实战------七、RESTful的详细介绍和使用 具体代码案例分析(一)
这篇文章详细介绍了RESTful的概念、实现方式,以及如何在SpringMVC中使用HiddenHttpMethodFilter来处理PUT和DELETE请求,并通过具体代码案例分析了RESTful的使用。
SpringMVC入门到实战------七、RESTful的详细介绍和使用 具体代码案例分析(一)
|
1月前
|
前端开发 应用服务中间件 数据库
SpringMVC入门到实战------八、RESTful案例。SpringMVC+thymeleaf+BootStrap+RestFul实现员工信息的增删改查
这篇文章通过一个具体的项目案例,详细讲解了如何使用SpringMVC、Thymeleaf、Bootstrap以及RESTful风格接口来实现员工信息的增删改查功能。文章提供了项目结构、配置文件、控制器、数据访问对象、实体类和前端页面的完整源码,并展示了实现效果的截图。项目的目的是锻炼使用RESTful风格的接口开发,虽然数据是假数据并未连接数据库,但提供了一个很好的实践机会。文章最后强调了这一章节主要是为了练习RESTful,其他方面暂不考虑。
SpringMVC入门到实战------八、RESTful案例。SpringMVC+thymeleaf+BootStrap+RestFul实现员工信息的增删改查
|
29天前
|
消息中间件 Java RocketMQ
微服务架构师的福音:深度解析Spring Cloud RocketMQ,打造高可靠消息驱动系统的不二之选!
【8月更文挑战第29天】Spring Cloud RocketMQ结合了Spring Cloud生态与RocketMQ消息中间件的优势,简化了RocketMQ在微服务中的集成,使开发者能更专注业务逻辑。通过配置依赖和连接信息,可轻松搭建消息生产和消费流程,支持消息过滤、转换及分布式事务等功能,确保微服务间解耦的同时,提升了系统的稳定性和效率。掌握其应用,有助于构建复杂分布式系统。
37 0
|
1月前
|
JSON 前端开发 Java
Spring MVC返回JSON数据
综上所述,Spring MVC提供了灵活、强大的方式来支持返回JSON数据,从直接使用 `@ResponseBody`及 `@RestController`注解,到通过配置消息转换器和异常处理器,开发人员可以根据具体需求选择合适的实现方式。
94 4
|
1月前
|
XML 前端开发 Java
Spring MVC接收param参数(直接接收、注解接收、集合接收、实体接收)
Spring MVC提供了灵活多样的参数接收方式,可以满足各种不同场景下的需求。了解并熟练运用这些基本的参数接收技巧,可以使得Web应用的开发更加方便、高效。同时,也是提高代码的可读性和维护性的关键所在。在实际开发过程中,根据具体需求选择最合适的参数接收方式,能够有效提升开发效率和应用性能。
80 3
|
1月前
|
XML 前端开发 Java
Spring MVC接收param参数(直接接收、注解接收、集合接收、实体接收)
Spring MVC提供了灵活多样的参数接收方式,可以满足各种不同场景下的需求。了解并熟练运用这些基本的参数接收技巧,可以使得Web应用的开发更加方便、高效。同时,也是提高代码的可读性和维护性的关键所在。在实际开发过程中,根据具体需求选择最合适的参数接收方式,能够有效提升开发效率和应用性能。
79 2
|
2月前
|
前端开发 Java 应用服务中间件
我以为我对Spring MVC很了解,直到我遇到了...
所有人都知道Spring MVC是是开发的,却鲜有人知道Spring MVC的理论基础来自于1978 年提出MVC模式的一个老头子,他就是Trygve Mikkjel Heyerdahl Reenskaug,挪威计算机科学家,名誉教授。Trygve Reenskaug的MVC架构思想早期用于图形用户界面(GUI) 的软件设计,他对MVC是这样解释的。MVC 被认为是解决用户控制大型复杂数据集问题的通用解决方案。最困难的部分是为不同的架构组件想出好的名字。模型-视图-编辑器是第一个。
111 1
我以为我对Spring MVC很了解,直到我遇到了...