使用annotation减少spring bean的配置

4 篇文章 0 订阅

本文转自:http://blog.csdn.net/dqatsh/article/details/3478000

发现一篇好文 http://www.ibm.com/developerworks/cn/java/j-lo-spring25-ioc/ 它给出了比本文更详细的说明。

springframework 2.5引入了完整的annotaion配置注解,使用这些annotation可以大量的减少bean的定义,也使得程序开发更简单和容易维护。

当然你要使用annotation就需要使用java5以上版本。

使用annotaion定义一个bean

@Component是一个通用注解,用于说明一个类是一个spring容器管理的类。
除此之外,还有@Controller@Service@Repository是@Component的细化,这三个注解比@Component带有更多的语义,它们分别对应了表现层、服务层、持久层的类。
如果你只是用它们定义bean,你可以仅使用@Component,但是既然spring提供这些细化的注解,那肯定有使用它们的好处,不过在以下的例子中体现不出。

定义了一个接口

  1. package test1;
  2. interface MovieFinder {
  3.     String getData();
  4. }
定义一个实现
  1. package test1;
  2. import org.springframework.stereotype.Repository;
  3. @Repository
  4. public class JpaMovieFinder implements MovieFinder {
  5.     @Override
  6.     public String getData() {
  7.         return "This is JpaMovieFinder implementation!";
  8.     }
  9. }
这里使用了注解 @Repository,说明这是一个受spring容器管理的bean定义,这个注解没有指定bean的名字,默认为小写开头的类名,就是jpaMovieFinder,如果你要指定名字,可以这样写@Repository("myMovieFinder")。
这里也可以使用@Component这个注解,在这里例子中体现不出用@Repository的好处。
这里没有指定这个bean的scope,缺省是singleton,如果你要其他scope,可以使用注解@Scope
  1. @Scope("prototype")
  2. @Repository
  3. public class MovieFinderImpl implements MovieFinder {
  4.     // ...
  5. }

spring扫描并注册注解的bean
JpaMovieFinder只是添加了一个注解,这并不会自动被注册到spring容器中,我们需要告诉spring容器到那里去寻找这些bean。
配置如下:
  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.        xmlns:context="http://www.springframework.org/schema/context"
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans 
  6.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  7.            http://www.springframework.org/schema/context
  8.            http://www.springframework.org/schema/context/spring-context-2.5.xsd">
  9.                
  10.      <context:component-scan base-package="test1"/>
  11.      
  12. </beans>
<context:component-scan base-package="test1"/>这个配置告诉spring容器到test1这个package下去扫描所有的类,从而找到被注解的类。
由于并不是test1下的所有的类都有注解,全部遍历效率不高,所以spring定义了过滤器用于减小扫描范围,这里为了简单起见没有使用。

使用注解进行依赖注入
  1. package test1;

  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.stereotype.Service;

  4. @Service
  5. public class SimpleMovieLister {
  6.     
  7.     @Autowired
  8.     private MovieFinder movieFinder;

  9.     public String getData(String name) {
  10.         return "Hi " + name + "! " + movieFinder.getData();
  11.     }
  12.     
  13.     public MovieFinder getMovieFinder() {
  14.         return movieFinder;
  15.     }

  16.     public void setMovieFinder(MovieFinder movieFinder) {
  17.         this.movieFinder = movieFinder;
  18.     }
  19. }
SimpleMovieLister是一个服务类,它也使用了@Service注解为了bean,这个类用到了MovieFinder,为了注入这个类的实现,这里使用了注解 @Autowired,spring容器会自动找到合适的bean注入进去。注意这里并没有指定被注入bean的名字,因为spring根据只发现了一个实现,那就是 jpaMovieFinder。后面,我们会看到有两个实现会怎样。

注意,上面代码使用@Autowired时,
public void setMovieFinder(MovieFinder movieFinder) 这个方法是不需要的,你可以把它删除了试一试。如果你使用xml的配置方式,该方法必须存在。我这里保留该方法,是为了后面测试注解和xml配置混合使用的方式。

测试1
  1. package test1;

  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;

  4. public class Main {

  5.     public static void main(String[] args) {
  6.         ApplicationContext context = new ClassPathXmlApplicationContext("test1/beans.xml");
  7.         SimpleMovieLister m = (SimpleMovieLister)context.getBean("simpleMovieLister");
  8.         System.out.println(m.getData("Arthur"));
  9.     }

  10. }

控制台上会打印 Hi Arthur! This is JpaMovieFinder implementation!

增加MovieFinder的第二个实现
  1. package test1;
  2. import org.springframework.stereotype.Repository;
  3. @Repository
  4. public class IbatisMovieFinder implements MovieFinder {
  5.     @Override
  6.     public String getData() {
  7.         return "This is IbatisMovieFinder implementation!";
  8.     }
  9. }

这时运行Main,系统会报错:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleMovieLister': Injection of resource fields failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [test1.MovieFinder] is defined: expected single matching bean but found 2: [jpaMovieFinder, ibatisMovieFinder]
从错误信息中我们可以看到现在MovieFinder有两个bean实现了,一个是
jpaMovieFinder,另一个是 ibatisMovieFinder,spring容器不知道应该使用哪一个bean。这时可以使用注解 @Qualifier指定具体的bean。
  1. //...
  2. @Service
  3. public class SimpleMovieLister {

  4.     @Autowired
  5.     @Qualifier("ibatisMovieFinder")
  6.     private MovieFinder movieFinder;
  7. //...
这里我们指定注入的是 ibatisMovieFinder这个bean。
运行Main, 
控制台上会打印 Hi Arthur! This is IbatisMovieFinder implementation!

Java6提供的注入注解
spring也可以使用java6提供的@Resource注解来指定注入哪一个bean。
  1. //...
  2. @Service
  3. public class SimpleMovieLister {
  4.     @Resource(name="ibatisMovieFinder")
  5.     private MovieFinder movieFinder;
  6. //...
这和@Autowired功能是一致的。

使用注解还是xml
使用注解很方便,但从上面的例子我们也可以看出注解的问题, MovieFinder有两个实现, SimpleMovieLister是在程序中用注解指定了使用哪一个实现,如果要修改,需要修改源程序。所以,注解只适用于固定依赖的情况。如果依赖需要在部署的时候做调整,那还是使用xml的配置方式方便,毕竟只需要修改一下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.        xmlns:context="http://www.springframework.org/schema/context"
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans 
  6.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  7.            http://www.springframework.org/schema/context
  8.            http://www.springframework.org/schema/context/spring-context-2.5.xsd">
  9.                
  10.     <context:component-scan base-package="test1"/>
  11.     
  12.     <bean id="simpleMovieLister1" class="test1.SimpleMovieLister">
  13.         <property name="movieFinder" ref="jpaMovieFinder" />
  14.     </bean>
  15.     
  16. </beans>
使用xml配置方式定义了另外一bean,注入了 jpaMovieFinder这个实现。

  1. package test1;

  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;

  4. public class Main {

  5.     public static void main(String[] args) {
  6.         ApplicationContext context = new ClassPathXmlApplicationContext("test1/beans.xml");
  7.         SimpleMovieLister m = (SimpleMovieLister)context.getBean("simpleMovieLister");
  8.         System.out.println(m.getData("Arthur"));
  9.         SimpleMovieLister m1 = (SimpleMovieLister)context.getBean("simpleMovieLister1");
  10.         System.out.println(m1.getData("Arthur"));
  11.     }

  12. }
simpleMovieLister是从注解来的, simpleMovieLister1是从xml配置来的。运行结果:
Hi Arthur! This is IbatisMovieFinder implementation!
Hi Arthur! This is JpaMovieFinder implementation!

证明混合使用是可行的,你可以继续测试,用xml重新配置
simpleMovieLister。
因此,即使我一开始使用了注解,之后我后悔了,没有关系,不用修改源程序,以前用xml怎么配置现在还是怎么配置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值