惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
G
Google Developers Blog
小众软件
小众软件
V
V2EX
月光博客
月光博客
腾讯CDC
aimingoo的专栏
aimingoo的专栏
J
Java Code Geeks
Y
Y Combinator Blog
人人都是产品经理
人人都是产品经理
B
Blog RSS Feed
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 【当耐特】
D
Docker
M
MIT News - Artificial intelligence
Google DeepMind News
Google DeepMind News
N
Netflix TechBlog - Medium
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
InfoQ
MongoDB | Blog
MongoDB | Blog
Apple Machine Learning Research
Apple Machine Learning Research
Jina AI
Jina AI

博客园 - Squall

struts2登录拦截器 Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AU hibernate.current_session_context_class 错误 - Squall - 博客园 Lucene中使用Paoding中文分词 ibatis VS hibernate 经典论述 超越传统软件开发技术 ASP 缩略图 (纠错版) persits.jpeg 破解版下载 Cant connect to SQL server with jtds 1.2.2 - Squall The hibernate core class ------ ExportToDB Struts+spring使用随机验证码 SSH 异常 解决 方案 总结 Struts-Logic 标签库 structs - 标签库(html) spring2.0 事务管理以及异常处理之体会 Could not open ServletContext resource [/WEB-INF/applicationContext.xml] myeclipse tomcat 部署错误 ASP 通过正则提取信息内容种的图片 div+css 绝对定位和相对定位
Spring2.5中基于注释的IoC
Squall · 2009-09-21 · via 博客园 - Squall

   注释的优势

       它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作。如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO 的属性名、类型等信息,如果关系表字段和 PO 属性名、类型都一致,您甚至无需编写任务属性映射信息——因为这些信息都可以通过 Java 反射机制获取。
       注释和 Java 代码位于一个文件中,而 XML 配置采用独立的配置文件,大多数配置信息在程序开发完成后都不会调整,如果配置信息和 Java 代码放在一起,有助于增强程序的内聚性。而采用独立的 XML 配置文件,程序员在编写一个功能时,往往需要在程序文件和配置文件中不停切换,这种思维上的不连贯会降低开发效率。
      

       因此在很多情况下,注释配置比 XML 配置更受欢迎,注释配置有进一步流行的趋势。Spring 2.5 的一大增强就是引入了很多注释类,现在您已经可以使用注释配置完成大部分XML 配置的功能。在这篇文章里,我们将向您讲述使用注释进行 Bean 定义和依赖注入的内容。

    原来我们是怎么做的

UserDAO.java:

Java代码 复制代码

  1. package com.tanlan.springdemo;   
  2. /**  
  3.  * UserDAO接口  
  4.  *   
  5.  * @author tanlan tl_smile@163.com  
  6.  *   
  7.  * @date 2009-8-3  
  8.  */  
  9. public interface UserDAO {   
  10.     public void addUser();   
  11. }  

 UserJDBCDAO.java:

Java代码 复制代码

  1. package com.tanlan.springdemo;   
  2. /**  
  3.  * UserDAO的JDBC实现  
  4.  *   
  5.  * @author tanlan tl_smile@163.com  
  6.  *   
  7.  * @date 2009-8-3  
  8.  */  
  9.   
  10. public class UserJDBCDAO implements UserDAO {   
  11.     public void addUser() {   
  12.         System.out.println("使用JDBC增加用户信息!");   
  13.     }   
  14.   
  15. }  

UserService.java:

Java代码 复制代码

  1. package com.tanlan.springdemo;   
  2. /**  
  3.  * User业务逻辑处理类  
  4.  *   
  5.  * @author tanlan tl_smile@163.com  
  6.  *   
  7.  * @date 2009-8-3  
  8.  */  
  9. public class UserService {   
  10.     private UserDAO userDAO;   
  11.   
  12.     public void addUser() {   
  13.         userDAO.addUser();   
  14.     }   
  15.   
  16.     public UserDAO getUserDAO() {   
  17.         return userDAO;   
  18.     }   
  19.   
  20.     public void setUserDAO(UserDAO userDAO) {   
  21.         this.userDAO = userDAO;   
  22.     }   
  23.   
  24. }  

 配置文件 spring.xml:
 

Xml代码 复制代码

  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 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  5.                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  6.     <bean id="userJdbcDAO" class="com.tanlan.springdemo.UserJDBCDAO"></bean>  
  7.     <bean id="userService" class="com.tanlan.springdemo.UserService">  
  8.         <property name="userDAO" ref="userJdbcDAO"></property>  
  9.     </bean>  
  10. </beans>  

 测试类Test.java:

Java代码 复制代码

  1. package com.tanlan.springdemo;   
  2.   
  3. import org.springframework.context.ApplicationContext;   
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  5.   
  6. public class Test {   
  7.   
  8.     public static void main(String[] args) {   
  9.         String[] files = { "spring.xml" };   
  10.         ApplicationContext context = new ClassPathXmlApplicationContext(files);   
  11.         UserService userService = (UserService) context.getBean("userService");   
  12.         userService.addUser();   
  13.     }   
  14.   
  15. }  

使用 @Autowired 注释

          Spring 2.5 引入了 @Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。

对UserService.java的改进:

Java代码 复制代码

  1. package com.tanlan.springdemo;   
  2.   
  3. import org.springframework.beans.factory.annotation.Autowired;   
  4.   
  5. /**  
  6.  * User业务逻辑处理类  
  7.  *   
  8.  * @author tanlan tl_smile@163.com  
  9.  *   
  10.  * @date 2009-8-3  
  11.  */  
  12. public class UserService {   
  13.     @Autowired  
  14.     private UserDAO userDAO;   
  15.   
  16.     public void addUser() {   
  17.         userDAO.addUser();   
  18.     }   
  19. }  

这个类甚至可以省略getter/setter.

配置文件spring.xml的改进:

Xml代码 复制代码

  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 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  5.                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  6.     <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"></bean>  
  7.     <bean id="userJdbcDAO" class="com.tanlan.springdemo.UserJDBCDAO"></bean>  
  8.     <bean id="userService" class="com.tanlan.springdemo.UserService"></bean>  
  9. </beans>  

      Spring 通过一个 BeanPostProcessor 对 @Autowired 进行解析,所以要让 @Autowired 起作用必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。

        UserService类的属性不需要配置了。

当候选 Bean 数目不为 1 时的应对方法

        在默认情况下使用 @Autowired 注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。当找不到一个匹配的 Bean 时,Spring 容器将抛出BeanCreationException 异常,并指出必须至少拥有一个匹配的 Bean。
       和找不到一个类型匹配 Bean 相反的一个错误是:如果 Spring 容器中拥有多个候选Bean,Spring 容器在启动时也会抛出 BeanCreationException 异常。
       Spring 允许我们通过 @Qualifier 注释指定注入 Bean 的名称

加入现在多了一个UserDAO的实现类

UserHibernateDAO.java:

Java代码 复制代码

  1. package com.tanlan.springdemo;   
  2.   
  3. /**  
  4.  * UserDAO的Hibernate实现  
  5.  *   
  6.  * @author tanlan tl_smile@163.com  
  7.  *   
  8.  * @date 2009-8-3  
  9.  */  
  10. public class UserHibernateDAO implements UserDAO {   
  11.     public void addUser() {   
  12.         System.out.println("使用Hibernate增加用户信息!");   
  13.     }   
  14. }  

更新spring.xml:

Xml代码 复制代码

  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 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  5.                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  6.     <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"></bean>  
  7.     <bean id="userJdbcDAO" class="com.tanlan.springdemo.UserJDBCDAO"></bean>  
  8.     <bean id="userHibernateDAO" class="com.tanlan.springdemo.UserHibernateDAO"></bean>  
  9.     <bean id="userService" class="com.tanlan.springdemo.UserService"></bean>  
  10. </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:

Java代码 复制代码

  1. package com.tanlan.springdemo;   
  2.   
  3. import org.springframework.beans.factory.annotation.Autowired;   
  4. import org.springframework.beans.factory.annotation.Qualifier;   
  5.   
  6. /**  
  7.  * User业务逻辑处理类  
  8.  *   
  9.  * @author tanlan tl_smile@163.com  
  10.  *   
  11.  * @date 2009-8-3  
  12.  */  
  13. public class UserService {   
  14.     @Autowired  
  15.     @Qualifier("userJdbcDAO")   
  16.     private UserDAO userDAO;   
  17.   
  18.     public void addUser() {   
  19.         userDAO.addUser();   
  20.     }   
  21. }  

使用 <context:annotation-config/> 简化配置

        Spring 2.1 添加了一个新的 context 的 Schema 命名空间,该命名空间对注释驱动、属性文件引入、加载期织入等功能提供了便捷的配置.

       改进spring.xml:

Xml代码 复制代码

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:context="http://www.springframework.org/schema/context"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  6.                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  7.     <context:annotation-config></context:annotation-config>  
  8.     <bean id="userJdbcDAO" class="com.tanlan.springdemo.UserJDBCDAO"></bean>  
  9.     <bean id="userHibernateDAO" class="com.tanlan.springdemo.UserHibernateDAO"></bean>  
  10.     <bean id="userService" class="com.tanlan.springdemo.UserService"></bean>  
  11. </beans>  

 注意命名空间:xmlns:context=http://www.springframework.org/schema/context的添加。

以及<context:annotation-config/>的使用。

使用 @Component

 Spring 2.5 提供的 @Component 注释可以定义 Bean,从 XML 配置文件中完全移除 Bean 定义的配置。

改进UserJDBCDAO.java:

Java代码 复制代码

  1. package com.tanlan.springdemo;   
  2.   
  3. import org.springframework.stereotype.Component;   
  4.   
  5. /**  
  6.  * UserDAO的JDBC实现  
  7.  *   
  8.  * @author tanlan tl_smile@163.com  
  9.  *   
  10.  * @date 2009-8-3  
  11.  */  
  12. @Component("userJdbcDAO")   
  13. public class UserJDBCDAO implements UserDAO {   
  14.     public void addUser() {   
  15.         System.out.println("使用JDBC增加用户信息!");   
  16.     }   
  17.   
  18. }  

改进UserHibernateDAO.java:

Java代码 复制代码

  1. package com.tanlan.springdemo;   
  2.   
  3. import org.springframework.stereotype.Component;   
  4.   
  5. /**  
  6.  * UserDAO的Hibernate实现  
  7.  *   
  8.  * @author tanlan tl_smile@163.com  
  9.  *   
  10.  * @date 2009-8-3  
  11.  */  
  12. @Component("userHibernateDAO")   
  13. public class UserHibernateDAO implements UserDAO {   
  14.     public void addUser() {   
  15.         System.out.println("使用Hibernate增加用户信息!");   
  16.     }   
  17. }  

改进UserService.java:

Java代码 复制代码

  1. package com.tanlan.springdemo;   
  2.   
  3. import org.springframework.beans.factory.annotation.Autowired;   
  4. import org.springframework.beans.factory.annotation.Qualifier;   
  5. import org.springframework.stereotype.Component;   
  6.   
  7. /**  
  8.  * User业务逻辑处理类  
  9.  *   
  10.  * @author tanlan tl_smile@163.com  
  11.  *   
  12.  * @date 2009-8-3  
  13.  */  
  14. @Component  
  15. public class UserService {   
  16.     @Autowired  
  17.     @Qualifier("userJdbcDAO")   
  18.     private UserDAO userDAO;   
  19.   
  20.     public void addUser() {   
  21.         userDAO.addUser();   
  22.     }   
  23. }  

改进spring.xml:

Xml代码 复制代码

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:context="http://www.springframework.org/schema/context"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  6.                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  7.     <context:component-scan base-package="com.tanlan.springdemo"></context:component-scan>  
  8. </beans>  

      在使用 @Component 注释后,Spring 容器必须启用类扫描机制以启用注释驱动 Bean 定义和注释驱动 Bean 自动注入的策略.
       <context:component-scan/> 的 base-package 属性指定了需要扫描的类包,类包及其递归子包中所有的类都会被处理.

注释配置和 XML 配置的适用场合

       是否有了这些 IOC 注释,我们就可以完全摒除原来 XML 配置的方式呢?答案是否定的。有以下几点原因:
       注释配置不一定在先天上优于 XML 配置。如果 Bean 的依赖关系是固定的,(如Service 使用了哪几个 DAO 类),这种配置信息不会在部署时发生调整,那么注释配置优于 XML 配置;反之如果这种依赖关系会在部署时发生调整,XML 配置显然又优于注释配置,因为注释是对 Java 源代码的调整,您需要重新改写源代码并重新编译才可以实施调整。
如果 Bean 不是自己编写的类(如 JdbcTemplate、SessionFactoryBean 等),注释配置将无法实施,此时 XML 配置是唯一可用的方式。
       注释配置往往是类级别的,而 XML 配置则可以表现得更加灵活。比如相比于@Transaction 事务注释,使用 aop/tx 命名空间的事务配置更加灵活和简单。
      

       所以在实现应用中,我们往往需要同时使用注释配置和 XML 配置,对于类级别且不会发生变动的配置可以优先考虑注释配置;而对于那些第三方类以及容易发生调整的配置则应优先考虑使用 XML 配置。Spring 会在具体实施 Bean 创建和 Bean 注入之前将这两种配置方式的元信息融合在一起。