`
kingtai168
  • 浏览: 26489 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

spring2.5注解驱动(一)

阅读更多
概述

注释配置相对于 XML 配置具有很多的优势:
它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作。如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO 的属性名、类型等信息,如果关系表字段和 PO 属性名、类型都一致,您甚至无需编写任务属性映射信息——因为这些信息都可以通过 Java 反射机制获取。
注释和 Java 代码位于一个文件中,而 XML 配置采用独立的配置文件,大多数配置信息在程序开发完成后都不会调整,如果配置信息和 Java 代码放在一起,有助于增强程序的内聚性。而采用独立的 XML 配置文件,程序员在编写一个功能时,往往需要在程序文件和配置文件中不停切换,这种思维上的不连贯会降低开发效率。
因此在很多情况下,注释配置比 XML 配置更受欢迎,注释配置有进一步流行的趋势。Spring 2.5 的一大增强就是引入了很多注释类,现在您已经可以使用注释配置完成大部分 XML 配置的功能。在这篇文章里,我们将向您讲述使用注释进行 Bean 定义和依赖注入的内容。

原来我们是怎么做的
在使用注释配置之前,先来回顾一下传统上是如何配置 Bean 并完成 Bean 之间依赖关系的建立。下面是 3 个类,它们分别是 Office、Car 和 Boss,这 3 个类需要在 Spring 容器中配置为 Bean:

Office 仅有一个属性:
清单 1. Office.java

 

Java代码
  1. package com.baobaotao;      
  2. public class Office {      
  3.     private String officeNo =”001”;      
  4.      
  5.     //省略 get/setter      
  6.      
  7.     @Override     
  8.     public String toString() {      
  9.         return "officeNo:" + officeNo;      
  10.     }      
  11. }    

Car 拥有两个属性:
清单 2. Car.java
Java代码
  1. package com.baobaotao;      
  2.      
  3. public class Car {      
  4.     private String brand;      
  5.     private double price;      
  6.      
  7.     // 省略 get/setter      
  8.      
  9.     @Override     
  10.     public String toString() {      
  11.         return "brand:" + brand + "," + "price:" + price;      
  12.     }      
  13. }   

Boss 拥有 Office 和 Car 类型的两个属性:
清单 3. Boss.java
Java代码
  1. package com.baobaotao;      
  2.      
  3. public class Boss {      
  4.     private Car car;      
  5.     private Office office;      
  6.      
  7.     // 省略 get/setter      
  8.      
  9.     @Override     
  10.     public String toString() {      
  11.         return "car:" + car + "\n" + "office:" + office;      
  12.     }      
  13. }    

我们在 Spring 容器中将 Office 和 Car 声明为 Bean,并注入到 Boss Bean 中:下面是使用传统 XML 完成这个工作的配置文件 beans.xml:
清单 4. beans.xml 将以上三个类配置成 Bean
Java代码
  1. <?xml version="1.0" encoding="UTF-8" ?>     
  2. <beans xmlns="http://www.springframework.org/schema/beans"     
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans       
  5.  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">     
  6.     <bean id="boss" class="com.baobaotao.Boss">     
  7.         <property name="car" ref="car"/>     
  8.         <property name="office" ref="office" />     
  9.     </bean>     
  10.     <bean id="office" class="com.baobaotao.Office">     
  11.         <property name="officeNo" value="002"/>     
  12.     </bean>     
  13.     <bean id="car" class="com.baobaotao.Car" scope="singleton">     
  14.         <property name="brand" value=" 红旗 CA72"/>     
  15.         <property name="price" value="2000"/>     
  16.     </bean>     
  17. </beans>    

当我们运行以下代码时,控制台将正确打出 boss 的信息:
清单 5. 测试类:AnnoIoCTest.java
Java代码
  1. import org.springframework.context.ApplicationContext;      
  2. import org.springframework.context.support.ClassPathXmlApplicationContext;      
  3. public class AnnoIoCTest {      
  4.      
  5.     public static void main(String[] args) {      
  6.         String[] locations = {"beans.xml"};      
  7.         ApplicationContext ctx =       
  8.             new ClassPathXmlApplicationContext(locations);      
  9.         Boss boss = (Boss) ctx.getBean("boss");      
  10.         System.out.println(boss);      
  11.     }      
  12. }   

这说明 Spring 容器已经正确完成了 Bean 创建和装配的工作。


使用 @Autowired 注释
Spring 2.5 引入了 @Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。来看一下使用 @Autowired 进行成员变量自动注入的代码:
清单 6. 使用 @Autowired 注释的 Boss.java
Java代码
  1. package com.baobaotao;      
  2. import org.springframework.beans.factory.annotation.Autowired;      
  3.      
  4. public class Boss {      
  5.      
  6.     @Autowired     
  7.     private Car car;      
  8.      
  9.     @Autowired     
  10.     private Office office;      
  11.      
  12.     …      
  13. }   

Spring 通过一个 BeanPostProcessor 对 @Autowired 进行解析,所以要让 @Autowired 起作用必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。
清单 7. 让 @Autowired 注释工作起来
Java代码
  1. <?xml version="1.0" encoding="UTF-8" ?>     
  2. <beans xmlns="http://www.springframework.org/schema/beans"     
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans       
  5.  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">     
  6.      
  7.     <!-- 该 BeanPostProcessor 将自动起作用,对标注 @Autowired 的 Bean 进行自动注入 -->     
  8.     <bean class="org.springframework.beans.factory.annotation.      
  9.         AutowiredAnnotationBeanPostProcessor"/>     
  10.      
  11.     <!-- 移除 boss Bean 的属性注入配置的信息 -->     
  12.     <bean id="boss" class="com.baobaotao.Boss"/>     
  13.        
  14.     <bean id="office" class="com.baobaotao.Office">     
  15.         <property name="officeNo" value="001"/>     
  16.     </bean>     
  17.     <bean id="car" class="com.baobaotao.Car" scope="singleton">     
  18.         <property name="brand" value=" 红旗 CA72"/>     
  19.         <property name="price" value="2000"/>     
  20.     </bean>     
  21. </beans>   

这样,当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中所有 Bean,当发现 Bean 中拥有 @Autowired 注释时就找到和其匹配(默认按类型匹配)的 Bean,并注入到对应的地方中去。

按照上面的配置,Spring 将直接采用 Java 反射机制对 Boss 中的 car 和 office 这两个私有成员变量进行自动注入。所以对成员变量使用 @Autowired 后,您大可将它们的 setter 方法(setCar() 和 setOffice())从 Boss 中删除。

当然,您也可以通过 @Autowired 对方法或构造函数进行标注,来看下面的代码
清单 8. 将 @Autowired 注释标注在 Setter 方法上

Java代码
  1. package com.baobaotao;      
  2.      
  3. public class Boss {      
  4.     private Car car;      
  5.     private Office office;      
  6.      
  7.      @Autowired     
  8.     public void setCar(Car car) {      
  9.         this.car = car;      
  10.     }      
  11.        
  12.     @Autowired     
  13.     public void setOffice(Office office) {      
  14.         this.office = office;      
  15.     }      
  16.     …      
  17. }    

这时,@Autowired 将查找被标注的方法的入参类型的 Bean,并调用方法自动注入这些 Bean。而下面的使用方法则对构造函数进行标注:
清单 9. 将 @Autowired 注释标注在构造函数上
Java代码
  1. package com.baobaotao;      
  2.      
  3. public class Boss {      
  4.     private Car car;      
  5.     private Office office;      
  6.        
  7.     @Autowired     
  8.     public Boss(Car car ,Office office){      
  9.         this.car = car;      
  10.         this.office = office ;      
  11.     }      
  12.        
  13.     …      
  14. }    

由于 Boss() 构造函数有两个入参,分别是 car 和 office,@Autowired 将分别寻找和它们类型匹配的 Bean,将它们作为 Boss(Car car ,Office office) 的入参来创建 Boss Bean。
当候选 Bean 数目不为 1 时的应对方法

在默认情况下使用 @Autowired 注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。当找不到一个匹配的 Bean 时,Spring 容器将抛出 BeanCreationException 异常,并指出必须至少拥有一个匹配的 Bean。我们可以来做一个实验:
清单 10. 候选 Bean 数目为 0 时
Java代码
  1. <?xml version="1.0" encoding="UTF-8" ?>     
  2. <beans xmlns="http://www.springframework.org/schema/beans"     
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
  4.      xsi:schemaLocation="http://www.springframework.org/schema/beans       
  5.  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd ">     
  6.        
  7.     <bean class="org.springframework.beans.factory.annotation.      
  8.         AutowiredAnnotationBeanPostProcessor"/>       
  9.      
  10.     <bean id="boss" class="com.baobaotao.Boss"/>     
  11.      
  12.     <!-- 将 office Bean 注释掉 -->     
  13.     <!-- <bean id="office" class="com.baobaotao.Office">     
  14.     <property name="officeNo" value="001"/>     
  15.     </bean>-->     
  16.      
  17.     <bean id="car" class="com.baobaotao.Car" scope="singleton">     
  18.         <property name="brand" value=" 红旗 CA72"/>     
  19.         <property name="price" value="2000"/>     
  20.     </bean>     
  21. </beans>   

由于 office Bean 被注释掉了,所以 Spring 容器中将没有类型为 Office 的 Bean 了,而 Boss 的 office 属性标注了 @Autowired,当启动 Spring 容器时,异常就产生了。

当不能确定 Spring 容器中一定拥有某个类的 Bean 时,可以在需要自动注入该类 Bean 的地方可以使用 @Autowired(required = false),这等于告诉 Spring:在找不到匹配 Bean 时也不报错。来看一下具体的例子:
清单 11. 使用 @Autowired(required = false)
Java代码
  1. package com.baobaotao;      
  2.      
  3. import org.springframework.beans.factory.annotation.Autowired;      
  4. import org.springframework.beans.factory.annotation.Required;      
  5.      
  6. public class Boss {      
  7.      
  8.     private Car car;      
  9.     private Office office;      
  10.      
  11.     @Autowired     
  12.     public void setCar(Car car) {      
  13.         this.car = car;      
  14.     }      
  15.     @Autowired(required = false)      
  16.     public void setOffice(Office office) {      
  17.         this.office = office;      
  18.     }      
  19.     …      
  20. }  

当然,一般情况下,使用 @Autowired 的地方都是需要注入 Bean 的,使用了自动注入而又允许不注入的情况一般仅会在开发期或测试期碰到(如为了快速启动 Spring 容器,仅引入一些模块的 Spring 配置文件),所以 @Autowired(required = false) 会很少用到。

和找不到一个类型匹配 Bean 相反的一个错误是:如果 Spring 容器中拥有多个候选 Bean,Spring 容器在启动时也会抛出 BeanCreationException 异常。来看下面的例子:
清单 12. 在 beans.xml 中配置两个 Office 类型的 Bean
Java代码
  1. <bean id="office" class="com.baobaotao.Office">     
  2.     <property name="officeNo" value="001"/>     
  3. </bean>     
  4. <bean id="office2" class="com.baobaotao.Office">     
  5.     <property name="officeNo" value="001"/>     
  6. </bean>    
我们在 Spring 容器中配置了两个类型为 Office 类型的 Bean,当对 Boss 的 office 成员变量进行自动注入时,Spring 容器将无法确定到底要用哪一个 Bean,因此异常发生了。

Spring 允许我们通过 @Qualifier 注释指定注入 Bean 的名称,这样歧义就消除了,可以通过下面的方法解决异常:
清单 13. 使用 @Qualifier 注释指定注入 Bean 的名称
Java代码
  1. @Autowired     
  2. public void setOffice(@Qualifier("office")Office office) {      
  3.     this.office = office;      
  4. }    

@Qualifier("office") 中的 office 是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。@Autowired 可以对成员变量、方法以及构造函数进行注释,而 @Qualifier 的标注对象是成员变量、方法入参、构造函数入参。正是由于注释对象的不同,所以 Spring 不将 @Autowired 和 @Qualifier 统一成一个注释类。下面是对成员变量和构造函数入参进行注释的代码:

对成员变量进行注释:
清单 14. 对成员变量使用 @Qualifier 注释 
Java代码
  1. public class Boss {      
  2.     @Autowired     
  3.     private Car car;      
  4.        
  5.     @Autowired     
  6.     @Qualifier("office")      
  7.     private Office office;      
  8.     …      
  9. }    

对构造函数入参进行注释:
清单 15. 对构造函数变量使用 @Qualifier 注释
Java代码
  1. public class Boss {      
  2.     private Car car;      
  3.     private Office office;      
  4.      
  5.     @Autowired     
  6.     public Boss(Car car , @Qualifier("office")Office office){      
  7.         this.car = car;      
  8.         this.office = office ;      
  9.     }      
  10. }   

@Qualifier 只能和 @Autowired 结合使用,是对 @Autowired 有益的补充。一般来讲,@Qualifier 对方法签名中入参进行注释会降低代码的可读性,而对成员变量注释则相对好一些。
使用 JSR-250 的注释
Spring 不但支持自己定义的 @Autowired 的注释,还支持几个由 JSR-250 规范定义的注释,它们分别是 @Resource、@PostConstruct 以及 @PreDestroy。

@Resource

@Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,面 @Resource 默认按 byName 自动注入罢了。@Resource 有两个属性是比较重要的,分别是 name 和 type,Spring 将 @Resource 注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。

Resource 注释类位于 Spring 发布包的 lib/j2ee/common-annotations.jar 类包中,因此在使用之前必须将其加入到项目的类库中。来看一个使用 @Resource 的例子:


清单 16. 使用 @Resource 注释的 Boss.java
Java代码
  1. package com.baobaotao;      
  2.      
  3. import javax.annotation.Resource;      
  4.      
  5. public class Boss {      
  6.     // 自动注入类型为 Car 的 Bean      
  7.     @Resource     
  8.     private Car car;      
  9.      
  10.     // 自动注入 bean 名称为 office 的 Bean      
  11.     @Resource(name = "office")      
  12.     private Office office;      
  13. }     

一般情况下,我们无需使用类似于 @Resource(type=Car.class) 的注释方式,因为 Bean 的类型信息可以通过 Java 反射从代码中获取。

要让 JSR-250 的注释生效,除了在 Bean 类中标注这些注释外,还需要在 Spring 容器中注册一个负责处理这些注释的 BeanPostProcessor:
Java代码
  1. <bean       
  2.   class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>    

CommonAnnotationBeanPostProcessor 实现了 BeanPostProcessor 接口,它负责扫描使用了 JSR-250 注释的 Bean,并对它们进行相应的操作。

@PostConstruct 和 @PreDestroy

Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,您既可以通过实现 InitializingBean/DisposableBean 接口来定制初始化之后 / 销毁之前的操作方法,也可以通过 <bean> 元素的 init-method/destroy-method 属性指定初始化之后 / 销毁之前调用的操作方法。关于 Spring 的生命周期,笔者在《精通 Spring 2.x—企业应用开发精解》第 3 章进行了详细的描述,有兴趣的读者可以查阅。

JSR-250 为初始化之后/销毁之前方法的指定定义了两个注释类,分别是 @PostConstruct 和 @PreDestroy,这两个注释只能应用于方法上。标注了 @PostConstruct 注释的方法将在类实例化后调用,而标注了 @PreDestroy 的方法将在类销毁之前调用。


清单 17. 使用 @PostConstruct 和 @PreDestroy 注释的 Boss.java
分享到:
评论
6 楼 lotnhiro 2013-04-13  
终于看懂一点了  谢谢分享
5 楼 niejun0205 2012-02-21  
very good!
4 楼 liberD 2010-12-31  
讲解的非常透彻!受用了!!
3 楼 java9920 2008-10-25  
java9920 写道

很不错!值得学习!

2 楼 java9920 2008-10-25  
很不错!值得学习!
1 楼 h_yz 2008-09-22  
学习了,谢谢大哥的分享

相关推荐

    spring2.5注解驱动

    在Spring 2.5版本中,引入了更加强大的注解驱动开发,大大简化了配置文件,提高了开发效率。让我们深入探讨一下Spring 2.5中的注解驱动技术。 首先,依赖注入是Spring的核心特性,它允许开发者通过接口定义组件间的...

    使用Spring 2.5 基于注解驱动的 Spring MVC详解

    使用 Spring 2.5 基于注解驱动的 Spring MVC 详解 本文将介绍 Spring 2.5 新增的 Spring MVC 注解功能,讲述如何使用注解配置替换传统的基于 XML 的 Spring MVC 配置。 Spring MVC 注解驱动 在 Spring 2.5 中,...

    Spring 2.5 基于注解驱动的Spring MVC

    Spring 2.5的注解驱动Spring MVC极大地简化了框架的配置和使用,使得开发人员可以更专注于业务逻辑,而不是繁琐的配置工作。这种面向切面编程(AOP)的特性,以及对注解的广泛支持,使得Spring MVC成为了一个更加...

    使用 Spring 2.5 基于注解驱动的 Spring.pdf

    Spring 2.5基于注解驱动的SpringMVC配置方式代表了现代Web应用开发的一个重要趋势——减少XML配置,增强代码的自描述性和可维护性。通过上述核心注解的使用,开发人员能够更快速、高效地构建响应式、可扩展的Web应用...

    使用 Spring 2.5 基于注解驱动的 Spring MVC

    注解驱动是Spring 2.5的一个重要特性,它简化了Spring MVC的应用程序开发过程。传统的Spring MVC应用程序通常需要在XML配置文件中进行大量的手动配置,包括定义各种Bean、配置请求映射等。这种方式虽然有效,但相对...

    使用 Spring 2.5 基于注解驱动的 Spring MVC.doc

    首先,Spring 2.5中的注解驱动的Spring MVC允许开发者摆脱对XML配置的依赖,从而减少了配置文件的复杂性。例如,传统的Spring MVC配置通常需要在`web.xml`中配置前端控制器(DispatcherServlet),并在Spring的应用...

    Spring2.5-中文参考手册chm

    在Spring 2.5中,Spring MVC引入了更多的注解驱动特性,简化了配置。 **数据访问集成** Spring 2.5增强了对多种数据访问技术的支持,包括JDBC、ORM(Object-Relational Mapping)框架如Hibernate和MyBatis等。它...

    spring2.5中文文档

    2. **注解驱动的开发**:Spring 2.5引入了大量的注解,如`@Controller`、`@Service`、`@Repository`和`@Component`,这些注解用于标记不同层的类,使代码更简洁,提高了可读性。 3. **AOP增强**:Spring的面向切面...

    spring2.5的所有jar包

    4. **注解驱动开发**:Spring 2.5大大增强了对Java注解的支持,如`@Service`、`@Repository`和`@Controller`,这些注解可以替代XML中的bean定义,简化配置。 5. **JSR-303数据校验**:Spring 2.5集成了JSR-303...

    Spring2.5 源代码

    Spring 2.5增加了对注解驱动的切面的支持,`@Aspect`、`@Before`、`@After`等注解使得AOP的使用更加直观。 4. **Bean工厂与ApplicationContext**: Spring 2.5中的Bean工厂是容器的基础,而ApplicationContext是更...

    spring2.5基于注解例子程序

    综上所述,这个"spring2.5基于注解的例子程序"涵盖了Spring 2.5的核心特性,包括注解驱动的配置、自动扫描、基于注解的事务管理、AOP支持、MVC框架的使用,以及依赖注入等。通过学习和理解这个例子,开发者可以更好...

    spring 2.5框架图

    在Spring 2.5中,AOP支持更灵活的切入点表达式和更多类型的切面,如注解驱动的切面,这使得AOP更加易用和强大。 3. **Beans包**:这是Spring框架的基础,包含Bean的定义、实例化、配置和管理。在Spring 2.5中,对...

    传智播客spring2.5源代码

    2. **注解驱动开发(Annotation-based Development)**:Spring 2.5开始大规模支持Java注解,比如`@Service`、`@Repository`和`@Controller`,它们分别用于标记业务层、数据访问层和控制层的组件。这使得XML配置文件...

    spring2.5中文文档(PDF)

    5. **Spring MVC**:Spring的Web MVC框架在2.5版本中也得到了优化,支持更多的注解驱动的控制器,如`@RequestMapping`、`@ResponseBody`等,简化了Web应用的开发。 6. **XML Schema支持**:Spring 2.5引入了新的XML...

    Spring2.5_基于注解驱动的SpringMVC

    Spring框架作为Java企业级开发中广泛使用的框架之一,自Spring2.0以来就对其MVC框架进行了重大的升级,到了Spring2.5版本更是引入了注解驱动的功能。这意味着开发者不再需要让Controller继承特定的接口或者在XML配置...

    spring 2.5依赖包

    1. **MVC框架**:Spring 2.5的Web MVC框架有了显著提升,支持注解驱动的控制器(@RequestMapping)和视图解析,使得Web应用的开发更为高效。 2. **RESTful支持**:Spring 2.5开始支持RESTful风格的Web服务,可以...

    spring2.5常用包

    9. **JMS(Java Message Service)支持**:Spring 2.5 支持消息驱动的应用,通过 JMSTemplate 和 MessageListener 接口,可以方便地实现消息队列的发送和接收。 10. **国际化(i18n)**:Spring 提供了 ...

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

    Spring 2.5 的一个重大改进是引入了全面的注解支持,这使得开发者在编写应用程序时可以减少XML配置,更加专注于业务逻辑。注释驱动的开发不仅提高了代码的可读性,还简化了项目结构,使得开发流程更加敏捷。基于注释...

    spring2.5 mvc_ibatis2

    3. Spring 2.5新特性:支持JSR-303 Bean Validation,提供注解驱动的事务管理,增强了AOP支持,以及对注解配置的进一步强化。 二、iBatis 2介绍 1. iBatis概念:iBatis是一个基于Java的持久层框架,它允许开发者...

Global site tag (gtag.js) - Google Analytics