写在前面:
好长时间没有写博客了,主要是最近一直忙于工做上面的事情没有研究什么新的东西,也没有什么写的,最近应一个朋友的邀请一块儿开发一套教材,我才有开始对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
参数绑定。