• 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> 对应的子类类型
      }
    }
  • 相关阅读:
    在普通类中调用service
    layui util 工具时间戳转换
    最大值
    药房管理
    线段树2
    线段树1
    Dijkstra
    最大值最小化
    图的M 着色问题
    取余运算
  • 原文地址:https://www.cnblogs.com/2015110615L/p/5575089.html
Copyright © 2020-2023  润新知