基于Annotation方式的Bean装配

6.2.6  基于Annotation方式的Bean装配

从JDK 5开始提供名为Annotation(注释)的功能,它被定义为JSR-175规范。在Java应用中,我们经常会遇到一些需要使用模板代码的情况。例如,为了编写一个JAX-RPC Web Service,我们必须提供一对接口和实现作为模板代码。如果使用Annotation对远程访问的方法代码进行修饰的话,这个模板就能够使用工具自动生成。另外,一些API需要使用与程序代码同时维护的附属文件。例如,JavaBeans需要一个BeanInfo Class与一个Bean同时使用/维护,而EJB则同样需要一个部署描述符,此时在程序中使用Annotation来维护这些附属文件的信息将十分便利而且减少了错误。

注释是以"@注释名"或"@注释名(参数名=参数值)"的形式在代码中存在的。例如,JDK 5内置的基本注释@Override 、@Deprecated 、@SuppressWarnings(value="unchecked")。注释可以附加在package、 class、method、 field等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问。如果没有外部解析工具等对其加以解析和处理的情况,本身不会对Java的源代码或class文件等产生任何影响,也不会对它们的执行产生任何影响。

在Spring中尽管使用XML配置文件可以完成所有的配置工作,直观表达Java EE程序员的"装配意图",但如果应用中Bean数量成千上万的话,最终会导致XML配置文件体积剧增,面对臃肿的XML配置文件,给维护与升级带来一定的困难。

那有没有一种行之有效的XML配置文件减肥方案呢?伟大的Spring开发团队想到了JDK 1.5提供的新特性--Annotation注释技术。从Spring 2.0开始,逐步完善对Annotation注释技术的全面支持,使XML配置文件不再臃肿,向"零配置"目标靠拢。

对于初学者而言,也许觉得Annotation注释技术太神秘了,随便放个注释就有如此巨大的威力。在了解了Annotation注释的工作原理之后,方觉得真正伟大的不是Annotation注释本身,而是幕后默默无闻地进行注释处理的Annotation处理器。Annotation注释仅仅是一个标记,用以表达程序员的某种意图,如果不为之量身开发一个Annotation处理器的话,Annotation注释本身将毫无意义,对程序也不会产生任何影响。Annotation处理器是基于JDK的反射机制来实现的,Spring 2.5中定义的一系列Annotation注释,如表6-4所示,幕后均有相应的Annotation处理器与之对应,最终实现Annotation注释的特定语义。

表6-4  Spring 2.5中常用的Annotation注释说明

注 释 名 称

功 能 描 述

@Autowired

通过@Autowired注解对Bean的属性变量、属性的Setter方法及构造函数进行标注,配合对应的注解处理器AutowiredAnnotationBeanProcessor完成Bean的自动配置工作。@Autowired注解默认是按Bean类型进行装配的,也就是说注解处理器AutowiredAnnotationBeanProcessor会在Spring容器中寻找与@Autowired注解所在属性同类型的Bean实例进行装配,如果找到多个满足条件的Bean实例时,将会抛出NoSuchBeanDefinitionException异常。@Autowired注解加上@Qualifier注解的话,可以直接指定一个Bean实例名称来进行装配。在实例应用中,不推荐使用@Autowired注解,因为该注解应用不当,会引发一些莫名其妙的问题

@Resource

@Resource的作用相当于@Autowired,配合对应的注解处理器CommonAnnotationBeanPostProcessor完成Bean的自动配置工作。只不过@Autowired注解默认是按Bean类型进行装配的,而@Resource注解默认是按Bean实例名称进行装配罢了。@Resource有两个属性是比较重要的,分别是nametypeSpring@Resource注解的name属性解析为Bean实例的名字,而type属性则解析为Bean实例的类型。所以如果使用name属性,则按Bean实例名称进行装配,而使用type属性时则按Bean类型进行装配。如果既不指定name也不指定type属性,这时则先按Bean实例名称进行装配,如果匹配不到,再按Bean类型进行装配,如果都匹配不到,则抛出NoSuchBeanDefinitionException异常

@Qualifier

如果@Autowired注解加上@Qualifier注解的话,可以将默认按Bean类型进行装配变换为按Bean实例名称进行装配,具体的Bean实例名称由@Qualifier注解的参数指定

@PostConstruct

Bean中的某个方法上加上@PostConstruct注解,则该方法将会在Bean初始化之后被Spring容器调用,作用等同在Spring配置文件中为bean标签指定init-method属性

@PreDestroy

Bean中的某个方法上加上@PreDestroy注解,则该方法将会在Bean实例被销毁之前由Spring容器进行调用,作用等同在Spring配置文件中为bean标签指定destroy-method属性

在Java EE中启用Spring的注解装配通常需要经过以下几个步骤。

(1)导入Spring注解装配功能所依赖的JAR包Jcommon-annotations.jar,并将其加入到当前项目的classpath中来,该文件在spring-framework-2.5.6\spring-framework-2.5.6 \lib\j2ee文件夹下可以找到;

(2)在Spring配置文件中定义context命名空间与相应的schemaLocation:

 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans  
  3. xmlns="http://www.springframework.org/schema/beans" 
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  5. xmlns:context="http://www.springframework.org/schema/context" 
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans   
  7. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
  8. http://www.springframework.org/schema/context  
  9. http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  10. ……  
  11. </beans> 

(3)在Spring配置文件中开启相应的注解处理器:

 
  1. <!-- 开启注解处理器 -->  
  2. <context:annotation-config/> 

(4)在Bean中使用表6-4中列举的Annotation注释进行Bean属性的自动装配。

下面我们以一个简单的Java应用SpringAnnotationIOC具体演示一下基于Annotation注解方式的Bean装配。

首先定义一个用于演示原型模式下Bean实例化的User类,User类中的随机数生成器rnd是通过@Autowired注解加@Qualifier注解实现按Bean实例名称注入的,User实例的ID是在initUser()方法中赋予的随机整数,initUser()使用@PostConstruct注解被指定为初始化时调用的方法:

 
  1. package test.spring.bean;  
  2. import java.util.Random;  
  3. import javax.annotation.PostConstruct;  
  4. import org.springframework.beans.factory.annotation.Autowired;  
  5. import org.springframework.beans.factory.annotation.Qualifier;  
  6. /** 用户持久化类 */ 
  7. public class User {  
  8. Integer id;//自然ID号  
  9. String userName;  //用户名  
  10. String userPwd;//用户密码  
  11. //使用@Autowired注解加@Qualifier注解实现按Bean实例名称装配  
  12. @Autowired @Qualifier("random")  
  13. Random rnd;  
  14. //默认构造方法  
  15. public User(){}  
  16. //使用@PostConstruct注解指定初始化时调用的方法  
  17. @PostConstruct 
  18. public void initUser() {  
  19. this.id = rnd.nextInt(1000);//产生一个1000以内的随机ID  
  20. this.userName ="用户"+this.id;//产生一个相应的用户名  
  21. this.userPwd = "123456";//指定一个初始化密码  
  22. }  
  23. //省略属性的get/set方法对  

接下来定义一个用于演示@Resource、@Autowired、@PostConstruct、@PreDestroy等注解用法的业务类AnnotationIocBean:

 
  1. package test.spring.bean;  
  2. import java.text.SimpleDateFormat;  
  3. import java.util.*;  
  4. import javax.annotation.PostConstruct;  
  5. import javax.annotation.PreDestroy;  
  6. import javax.annotation.Resource;  
  7. import org.springframework.beans.factory.annotation.Autowired;  
  8. /** 用于演示XML方式装配Bean实例的测试类 */ 
  9. public class AnnotationIocBean {  
  10. //定义两个通过@Resource注解注入的属性,可省略set方法  
  11. @Resource Date now;  
  12. //为@Resource注解指定name属性,直接引用Bean工厂中的一个Bean实例  
  13. @Resource(name="simpleDateFormat")  
  14. SimpleDateFormat sf;  
  15. //定义User类型的属性,通过Annotation注解方式注入  
  16. User user1;  
  17. //定义两个通过@Autowired注解注入的属性,可省略set方法  
  18. @Autowired User user2;  
  19. @Autowired User user3;  
  20. //缺省构造方法  
  21. public AnnotationIocBean() {}  
  22. //使用@PostConstruct注解指定初始化时调用的方法  
  23. @PostConstruct 
  24. public void init() {  
  25. System.out.println("AnnotationIocBean被实例化了!");  
  26. }  
  27. //定义一个业务方法输出各属性值  
  28. public void execute(){  
  29. System.out.println("现在的时间是:"+sf.format(now));  
  30. System.out.println("第一个用户ID="+user1.getId());  
  31. System.out.println("第二个用户ID="+user2.getId());  
  32. System.out.println("第三个用户ID="+user3.getId());  
  33. }  
  34. //使用@PreDestroy注解指定实例销毁时调用的方法  
  35. @PreDestroy 
  36. public void destroy() {  
  37. System.out.println("AnnotationIocBean实例被销毁了!");  
  38. }  
  39. //通过在set方法上放置@Resource注解实现注解方式注入  
  40. @Resource 
  41. public void setUser1(User user) {  
  42. this.user1 = user;  
  43. }  

下面在Spring的XML配置文件中配置相关Bean的装配信息,与以前基于XML方式装配Bean相比,配置文件中节省了大量的property标记,从而使配置文件得以瘦身:

 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans  
  3. xmlns="http://www.springframework.org/schema/beans" 
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  5. xmlns:context="http://www.springframework.org/schema/context" 
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans   
  7. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
  8. http://www.springframework.org/schema/context  
  9. http://www.springframework.org/schema/context/spring-context-2.5.xsd">      
  10. <!-- 开启注解处理器 -->  
  11. <context:annotation-config/>      
  12. <!-- 通过构造方法注入属性值装配SimpleDateFormat单实例 -->  
  13. <bean id="simpleDateFormat" class="java.text.SimpleDateFormat">  
  14. <!-- 在注入构造参数时,如果只有一个字符串类型的参数,  
  15. 则可省略index与type属性 -->  
  16. <constructor-arg value="yyyy年MM月dd hh时mm分ss秒" />  
  17. </bean>  
  18. <!-- 使用单例模式装配Date实例 -->  
  19. <bean id="now" class="java.util.Date"/>  
  20. <!-- 使用单例模式装配Random实例 -->  
  21. <bean id="random" class="java.util.Random"/>  
  22. <!-- 使用原型模式装配User实例,  
  23. 每次调用时都会生成一个全新的User实例 -->  
  24. <bean id="user" class="test.spring.bean.User" scope="prototype"/>  
  25. <!-- 使用单例模式装配XmlIocBean实例,  
  26. 实例属性通过Annotation注解方式注入 -->  
  27. <bean id="annotationIocBean" class="test.  
  28. spring.bean.AnnotationIocBean" />  
  29. </beans> 

最后编写AnnotationIocBean类的Junit测试用例testAnnotationIocBean:

 
  1. package test.spring.junit;  
  2. import org.junit.BeforeClass;  
  3. import org.junit.Test;  
  4. import org.springframework.context.support.  
  5. AbstractApplicationContext;  
  6. import org.springframework.context.support.  
  7. ClassPathXmlApplicationContext;  
  8. import test.spring.bean.AnnotationIocBean;  
  9. /** 业务控制器AnnotationIocBean的测试用例 */ 
  10. public class testAnnotationIocBean {  
  11. static AbstractApplicationContext cxt;  
  12. static AnnotationIocBean annotationIocBean;  
  13. //初始化ApplicationContext容器  
  14. @BeforeClass 
  15. public static void setUpBeforeClass() throws Exception {  
  16. //使用ClassPathXmlApplicationContext方式初始化ApplicationContext容器  
  17. cxt = new ClassPathXmlApplicationContext("applicationContext.xml");  
  18. //从Bean工厂容器中获取名为"annotationIocBean"的AnnotationIocBean实例  
  19. annotationIocBean = (AnnotationIocBean)cxt.getBean("annotationIocBean");  
  20. }  
  21. //测试AnnotationIocBean的execute方法  
  22. @Test 
  23. public void testExecute() {  
  24. annotationIocBean.execute();  
  25. //手动关闭Sping容器  
  26. cxt.close();  
  27. }  

测试用例的运行效果如图6-10所示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值