Spring2.5中基于注释的IoC
注释的优势
?????? 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作。如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO 的属性名、类型等信息,如果关系表字段和 PO 属性名、类型都一致,您甚至无需编写任务属性映射信息——因为这些信息都可以通过 Java 反射机制获取。
???????注释和 Java 代码位于一个文件中,而 XML 配置采用独立的配置文件,大多数配置信息在程序开发完成后都不会调整,如果配置信息和 Java 代码放在一起,有助于增强程序的内聚性。而采用独立的 XML 配置文件,程序员在编写一个功能时,往往需要在程序文件和配置文件中不停切换,这种思维上的不连贯会降低开发效率。
??????
?????? 因此在很多情况下,注释配置比 XML 配置更受欢迎,注释配置有进一步流行的趋势。Spring 2.5 的一大增强就是引入了很多注释类,现在您已经可以使用注释配置完成大部分XML 配置的功能。在这篇文章里,我们将向您讲述使用注释进行 Bean 定义和依赖注入的内容。
原来我们是怎么做的
UserDAO.java:
Java代码package?com.tanlan.springdemo; ??
?*/??
public?interface?UserDAO?{ ??
????public?void?addUser();???
}?
UserJDBCDAO.java
package?com.tanlan.springdemo;
public?class?UserJDBCDAO?implements?UserDAO?{ ??
????public?void?addUser()?{ ??
????????System.out.println("使用JDBC增加用户信息!"); ??
????}??????
}?
?
?
UserService.java
?
package?com.tanlan.springdemo;?
?
public?class?UserService?{
private?UserDAO?userDAO;???
public?void?addUser()?{ ?? ?
????????userDAO.addUser(); ??
}??
public?UserDAO?getUserDAO()?{ ??
????????return?userDAO; ??
}
public?void?setUserDAO(UserDAO?userDAO)?{ ??
????????this.userDAO?=?userDAO; ??
}?
??
}
配置文件 spring.xml:
?测试类Test.java:
package?com.tanlan.springdemo; ?? ?? import?org.springframework.context.ApplicationContext; ?? import?org.springframework.context.support.ClassPathXmlApplicationContext; ?? ?? public?class?Test?{ ?? ?? ????public?static?void?main(String[]?args)?{ ?? ????????String[]?files?=?{?"spring.xml"?}; ?? ????????ApplicationContext?context?=?new?ClassPathXmlApplicationContext(files); ?? ????????UserService?userService?=?(UserService)?context.getBean("userService"); ?? ????????userService.addUser(); ?? ????} ?? ?? }???
使用 @Autowired 注释??????????Spring 2.5 引入了 @Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。
?
对UserService.java的改进:
这个类甚至可以省略getter/setter.
?
配置文件spring.xml的改进:
??????? UserService类的属性不需要配置了。
当候选 Bean 数目不为 1 时的应对方法??????? 在默认情况下使用 @Autowired 注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。当找不到一个匹配的 Bean 时,Spring 容器将抛出BeanCreationException 异常,并指出必须至少拥有一个匹配的 Bean。
?????? 和找不到一个类型匹配 Bean 相反的一个错误是:如果 Spring 容器中拥有多个候选Bean,Spring 容器在启动时也会抛出 BeanCreationException 异常。
?????? Spring 允许我们通过 @Qualifier 注释指定注入 Bean 的名称
加入现在多了一个UserDAO的实现类
UserHibernateDAO.java:
package?com.tanlan.springdemo;??? public?class?UserHibernateDAO?implements?UserDAO?{ ?? ????public?void?addUser()?{ ?? ????????System.out.println("使用Hibernate增加用户信息!"); ?? ????} ?? }??更新spring.xml:
<?xml?version="1.0"?encoding="UTF-8"?>?? <beans?xmlns="http://www.springframework.org/schema/beans"?? ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?? ????xsi:schemaLocation="http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans-2.5.xsd ?? ????????????????http://www.springframework.org/schema/context?http://www.springframework.org/schema/context/spring-context-2.5.xsd">?? ????<bean?class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"></bean>?? ????<bean?id="userJdbcDAO"?class="com.tanlan.springdemo.UserJDBCDAO"></bean>?? ????<bean?id="userHibernateDAO"?class="com.tanlan.springdemo.UserHibernateDAO"></bean>?? ????<bean?id="userService"?class="com.tanlan.springdemo.UserService"></bean>?? </beans>?当Spring自动找寻UserDAO类型的类时,会找到两个符合要求的类:
?No unique bean of type [com.tanlan.springdemo.UserDAO] is defined: expected single matching bean but found 2: [userJdbcDAO, userHibernateDAO]
?
需要改进UserService.java:
package?com.tanlan.springdemo; ?? ?? import?org.springframework.beans.factory.annotation.Autowired; ?? import?org.springframework.beans.factory.annotation.Qualifier; ?? ?? public?class?UserService?{ ?? ????@Autowired?? ????@Qualifier("userJdbcDAO") ?? ????private?UserDAO?userDAO; ?? ?? ????public?void?addUser()?{ ?? ????????userDAO.addUser(); ?? ????} ?? }??使用 <context:annotation-config/> 简化配置??????? Spring 2.1 添加了一个新的 context 的 Schema 命名空间,该命名空间对注释驱动、属性文件引入、加载期织入等功能提供了便捷的配置.
?????? 改进spring.xml:
?注意命名空间:xmlns:context=http://www.springframework.org/schema/context的添加。
以及<context:annotation-config/>的使用。
使用 @Component?Spring 2.5 提供的 @Component 注释可以定义 Bean,从 XML 配置文件中完全移除 Bean 定义的配置。
改进UserJDBCDAO.java:
package?com.tanlan.springdemo; ?? ?? import?org.springframework.stereotype.Component;??? @Component("userJdbcDAO") ?? public?class?UserJDBCDAO?implements?UserDAO?{ ?? ????public?void?addUser()?{ ?? ????????System.out.println("使用JDBC增加用户信息!"); ?? ????} ?? ?? }??改进UserHibernateDAO.java:
package?com.tanlan.springdemo; ?? ?? import?org.springframework.stereotype.Component; @Component("userHibernateDAO") ?? public?class?UserHibernateDAO?implements?UserDAO?{ ?? ????public?void?addUser()?{ ?? ????????System.out.println("使用Hibernate增加用户信息!"); ?? ????} ?? }??改进UserService.java:
package?com.tanlan.springdemo; ?? ?? import?org.springframework.beans.factory.annotation.Autowired; ?? import?org.springframework.beans.factory.annotation.Qualifier; ?? import?org.springframework.stereotype.Component;??? @Component?? public?class?UserService?{ ?? ????@Autowired?? ????@Qualifier("userJdbcDAO") ?? ????private?UserDAO?userDAO; ?? ?? ????public?void?addUser()?{ ?? ????????userDAO.addUser(); ?? ????} ?? }??改进spring.xml:
???????是否有了这些 IOC 注释,我们就可以完全摒除原来 XML 配置的方式呢?答案是否定的。有以下几点原因:
?????? 注释配置不一定在先天上优于 XML 配置。如果 Bean 的依赖关系是固定的,(如Service 使用了哪几个 DAO 类),这种配置信息不会在部署时发生调整,那么注释配置优于 XML 配置;反之如果这种依赖关系会在部署时发生调整,XML 配置显然又优于注释配置,因为注释是对 Java 源代码的调整,您需要重新改写源代码并重新编译才可以实施调整。
如果 Bean 不是自己编写的类(如 JdbcTemplate、SessionFactoryBean 等),注释配置将无法实施,此时 XML 配置是唯一可用的方式。
?????? 注释配置往往是类级别的,而 XML 配置则可以表现得更加灵活。比如相比于@Transaction 事务注释,使用 aop/tx 命名空间的事务配置更加灵活和简单。
??????
?????? 所以在实现应用中,我们往往需要同时使用注释配置和 XML 配置,对于类级别且不会发生变动的配置可以优先考虑注释配置;而对于那些第三方类以及容易发生调整的配置则应优先考虑使用 XML 配置。Spring 会在具体实施 Bean 创建和 Bean 注入之前将这两种配置方式的元信息融合在一起。
?
?
??