Spring框架学习四:基于注解的方式对bean进行配置

 

除了使用XML文件方式来配置 bean 之外,我们还可以使用基于注解的方法来对 bean 进行配置

组件扫描(component scanning):Spring 能从classpath 下自动扫描、侦测和实例化具有特定注解的组件。

特定组件包括:

1. @Component:基本注解,标识一个受 Spring 管理的组件

2. @Repository:标识持久层组件

3. @Service:标识服务层(业务层)组件

4. @Controller:标识表现层组件

如果扫描到上述的特定注解,则spring会自动把这些类注册为bean

对于扫描到的组件,Spring 有默认的命名策略:使用非限定类名,第一个字母小写(即User类生成的对象名字为user)。也可以在注解中通过 value 属性值标识组件的名称,例如 @Component(value="自定义对象名字") 或直接定义为 @Component("自定义对象名字")

 

当在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明 <context:component-scan> 元素,它的使用规则如下:

1. base-package 属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及其子包中的所有类

2. 当需要扫描多个包时,可以使用逗号分隔

3. 如果希望扫描特定的类而非基包下的所有类,可以使用 resource-pattern 属性过滤特定的类,如

   <!-- 指定扫描 annotation 的子包 autowire 下所有的类 --> 
  <context:component-scan base-package="com.bupt.spring.annotation" resource-pattern="autowire/*.class"/>

4. <context:include-filter> 子节点表示要包含的目标类

5. <context:exclude-filter> 子节点表示要排除在外的目标类

6. <context:component-scan> 下可以拥有若干个 <context:include-filter> 和 <context:exclude-filter> 子节点

7. <context:include-filter> 和 <context:exclude-filter> 子节点支持多种类型(type)的过滤表达式(常用的为第一、二个):

类别 示例 说明
  annotation   com.spring.XxxAnnotation  所有标注了XxxAnnotation的类该类型采用目标类是否标注了某个注解进行过虑(根据注解进行过滤)
assignable com.spring.XxxService 所有继承或扩展XxxService的类该类型采用目标类是否继承或扩展某个特定类进行过滤(根据具体的类或接口进行过滤)
aspectj com.spring..*Service+ 所有类名以Service结束的类及继承或者扩展他们的类,该类型采用AspectJ表达式进行过滤
regex com.\spring\.anno\..* 所有com.spring.anno包下的类,该类型采用正则表达式根据类的名字进行过滤
custom com.spring.XxxTypeFilter 采用XxxTyperFilter通过代码的方式定义过滤规则,该类型必须实现org.springframework.core.type.TypeFilter接口
    <!-- 指定过滤 annotation 包及其子包下所有标注有 @Repository 的类,将它们排除在扫描之外 -->
    <context:component-scan base-package="com.bupt.springtest.annotation">
        <context:exclude-filter type="annotation" 
        expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
    <!-- 指定过滤 annotation 包及其子包下所有标注有 @Repository 的类,指定只扫描这些类,需要和 use-default-filters 配合使用-->
    <!-- 
        use-default-filters 默认为true,它会扫描 annotation 包及其子包下标有那四种注解的类。
        将其设为false,则只会去扫描满足 context:include-filter 条件的注解 ,其它的不再扫描
    -->
    <context:component-scan base-package="com.bupt.springtest.annotation" use-default-filters="false">
        <context:include-filter type="annotation" 
        expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
    <!-- 指定不扫描 UserRepository 类及其子类 -->
    <context:component-scan base-package="com.bupt.springtest.annotation">
        <context:exclude-filter type="assignable" 
        expression="com.bupt.springtest.annotation.repository.UserRepository"/>
    </context:component-scan>
    <!-- 指定只扫描 UserRepository 类及其子类 -->
    <context:component-scan base-package="com.bupt.springtest.annotation" use-default-filters="false">
        <context:include-filter type="assignable" 
        expression="com.bupt.springtest.annotation.repository.UserRepository"/>
    </context:component-scan>

 

除了将标注了注解的 bean 交付给 IoC 容器管理,注解还可用于标注 bean 与 bean 之间的关联关系

<context:component-scan> 元素还会自动注册 AutowiredAnnotationBeanPostProcessor 实例,该实例可以自动装配具有 @Autowired(推荐使用) @Resource 以及 @Inject 注解的属性。

<context:annotation-config> 元素也可用于注册 BeanPostProcessor 实例,但它们存在区别,而且 <context:component-scan> 能做的事情更多。它们之间具体的差异可以参照 http://blog.csdn.net/baple/article/details/16864835

 

下面分别介绍这几种属性用法:

@Autowired(默认按照类型进行注入) 注解自动装配具有兼容类型的单个 bean 属性,它具有以下特点:

1. 构造器,普通字段(即使是非public),一切具有参数的方法(如:setXxx方法上)都可以应用 @Autowired 注解

2. 默认情况下,所有使用 @Autowired 注解的属性都需要被设置。否则当Spring找不到匹配的 bean 装配属性时,会抛出异常。若某一属性允许不被设置,可以设置 @Autowired 注解的 required 属性为 false ( @Autowired(required=false) ),此时若找不到匹配的 bean 装配,则不会抛出异常。

3. 默认情况下,当IoC容器里面存在多个类型兼容的 bean 时,通过类型的自动装配将无法工作,此时可以在 @Qualifier 注解里提供 bean 的名称。Spring允许对方法的入参标注 @Qualifier 以指定注入 bean 的名称

 

//方法一:对类型 UserRepository 进行实例化,且对象名字叫 userRepository,后面注入时可以使用 @Resource(name="userRepository")
@Repository("userRepository")
public class UserRepositoryImp1 implements UserRepository
{
    @Override
    public void save()
    {
        //...
    }
}

@Repository
class UserRepositoryImp2 implements UserRepository
{
    @Override
    public void save()
    {
        //...
    }
}
@Service
public class UserService
{
    //方法二:通过@Qualifier指定装配的是哪个bean
    @Autowired
    @Qualifier("userRepositoryImp2")
    private UserRepository userRepository;

    /*
     * 也可以这样写,写在set方法上面
      @Autowired
      @Qualifier("userRepositoryImp2")
      public void setUserRepository(UserRepository userRepository)
      {
          this.userRepository = userRepository;
      }
      或者这样写
      @Autowired
      public void setUserRepository(@Qualifier("userRepositoryImp2")UserRepository userRepository)
      {
          this.userRepository = userRepository;
      }
    */

    public void add()
    {
        userRepository.save();
    }
}

 

4. @Autowired 注解也可以应用在数组类型的属性上,此时,Spring将会把所有匹配的 bean 进行自动装配

5. @Autowired 注解也可以应用在集合类型的属性上,此时Spring读取该集合的类型信息,然后自动装配与之兼容的 bean

6. @Autowired 注解用在 java.util.Map上时,若该Map的键值为String,那么Spring将自动装配与之 Map 值兼容的 bean,此时 bean的名称作为键值

@Resource 和 @Inject 注解的功能与 @Resource 类似

@Resource(默认按照名称注入) 要求提供一个 name = bean名称 的属性,若该属性为空,则自动采用标注处的变量或方法名作为 bean 的名称。若无名称匹配,则按类型注入

@Inject 和 @Autowired 注解一样也是按类型匹配注入的 bean,但没有 required 属性

 

既然可以使用注解为 Spring 的 bean 自动装配其他 bean 的引用,我们同样希望能够使用注解来装配简单的值。Spring 3.0 引入了 @Value,它是一个新的装配注解,可以让我们使用注解装配 String 类型的值和基本类型的值,如 int、boolean。

我们可以通过 @Value 直接标注某个属性、方法或者方法参数,并传入一个 String 类型的表达式来装配属性,如:

@Value("Eruption")
private String song;

实际上装配简单的值并不是 @Value 擅长的,它不仅仅可以装配一个静态值,它是一种有效的基于注解驱动的装配方式,它可以根据SpEL表达式来进行动态的求值计算,如:

@Value("#{systemProperties.myFavouriteSong}")
private String song;

 

 

Spring 4.x 新特性:泛型依赖注入

Spring 4.x 中可以为子类注入子类对应的泛型类型的成员变量

package com.bupt.springtest.annotation;

public class User{

}
package com.bupt.springtest.annotation;

public class BaseRepository<T>{
    
}
package com.bupt.springtest.annotation;
import org.springframework.beans.factory.annotation.Autowired;

public class BaseService<T>
{
    //属性会被子类继承
    @Autowired
    private BaseRepository<T> repository;
    
    public void add()
    {
        System.out.println(repository);
    }
}
@Repository
public class UserRepository extends BaseRepository<User>{
    
}
@Service
public class UserService extends BaseService<User>{

}
<context:component-scan base-package="com.bupt.springtest.annotation"/>
public class AnnotationTest
{
    public static void main(String[] args)
    {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        
        BaseService userService = (BaseService) ctx.getBean("userService");
        
        userService.add();
     
     //打印结果:com.bupt.springtest.annotation.UserRepository@1b0d3ed,即在
BaseService<T> 中,注入的 repository 属性的真正的类型是其子类的类型
     //因为在获取 userService 时确定了泛型 T 为 User,真正注入 repository 属性的是 <T> 对应的子类类型
  }
}

 

posted on 2016-06-14 11:46  Traveling_Light_CC  阅读(310)  评论(0编辑  收藏  举报

导航