zoukankan      html  css  js  c++  java
  • spring自动注入的三种方式

    所谓spring自动注入,是指容器中的一个组件中需要用到另一个组件(例如聚合关系)时,依靠spring容器创建对象,而不是手动创建,主要有三种方式:
    1. @Autowired注解——由spring提供
    2. @Resource注解——由JSR-250提供
    3. @Inject注解——由JSR-330提供
     
    @Autowired注解的使用方法
    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
    
       /**
        * Declares whether the annotated dependency is required.
        * <p>Defaults to {@code true}.
        */
       boolean required() default true;
    
    }
    从源码可以看出:该注解可以用在构造器、方法、参数、属性上,最常见的是用在属性上。
    该注解只有一个属性: required,默认为true,如果找不到匹配的bean则报错;设置为false,如果找不到匹配的bean则注入null,并不会报错。
    可以配合@Qualifier使用,用于精准指定要注入的bean的名称。
    可以配合@Primary使用,当容器中存在多个相同类型的组件时,用于指定优先加载哪一个,这个注解不能用在2个或更多同类型的组件上。
     
    1. 当容器中只有一个该类型的组件时
    |-不使用@Qualifier,会按bean类型查找,即applicationContext.getBean(bean.class),然后注入这个唯一的bean。
    |-使用@Qualifier,会按Qualifier的value值跟bean名称匹配查找,即applicationContext.getBean("Qualifier的value值")。
    2. 当容器中没有该类型的组件时
    |-required=true——报错expected at least 1 bean which qualifies as autowire candidate。
    |-required=false——注入null。
    3. 当容器中存在多个该类型的组件时
    |-不使用@Qualifier和@Primary时,会按属性名跟bean名称匹配查找,即applicationContext.getBean("属性名")。
    |-使用@Primary、但不使用@Qualifier时,会优先加载带有@Primary注解的组件。
    |-使用@Qualifier时,不管有没有使用@Primary,都会直接按Qualifier的value值跟bean名称匹配查找。
    综上,当容器中存在多个同类型的组件时,加载优先级:@Qulifier>@Primary>属性名,例如下面这个容器中包含3个BookDao组件
    @Configuration
    @ComponentScan(basePackages = {"cn.monolog.service"})
    public class AutowiredBeanConfig {
    
        @Bean(value = "bookDao1")
        public BookDao bookDao1() {
            BookDao bookDao = new BookDao();
            bookDao.setLabel("bookDao1");
            return bookDao;
        }
    
        @Bean(value = "bookDao2")
        @Primary
        public BookDao bookDao2() {
            BookDao bookDao = new BookDao();
            bookDao.setLabel("bookDao2");
            return bookDao;
        }
    
        @Bean(value = "bookDao3")
        public BookDao bookDao3() {
            BookDao bookDao = new BookDao();
            bookDao.setLabel("bookDao3");
            return bookDao;
        }
    }
    自动注入方式是这样的:
    @Autowired
    @Qualifier(value = "bookDao1")
    private BookDao bookDao3;
    按照优先级顺序,@Qulifier(bookDao1) > @Primary(bookDao2) > 属性名(bookDao3),最终加载的是名称为bookDao1的组件。
     

    @Resource注解的使用方法
    @Resource注解的使用跟@Autowired注解类似,但是需要注意:
    1. 不支持@Primary注解,也不支持reuqired=false,即不允许注入null;
    2. 该注解有一个属性name,类似于@Qualified精准匹配,优先级最高;
    3. 默认按照属性名跟bean的名称匹配查找,如果不存在,再按类型匹配查找。
    例如,下面这个容器中有两个CarDao组件
    @Configuration
    @ComponentScan(basePackages = {"cn.monolog.service"})
    public class ResourceBeanConfig {
    
        @Bean(value = "carDao1")
        public CarDao carDao1() {
            CarDao carDao = new CarDao();
            carDao.setLabel("1");
            return  carDao;
        }
    
        @Bean(value = "carDao2")
        public CarDao carDao() {
            CarDao carDao = new CarDao();
            carDao.setLabel("2");
            return  carDao;
        }
    }
    自动注入方式如下,会按属性名注入carDao2组件。
    //自动注入
    @Resource
    private CarDao carDao2;
    但是改为下面这种注入方式:
    //自动注入
    @Resource(name = "carDao1")
    private CarDao carDao2;
    由于使用了name精准匹配,会忽略属性名,注入carDao1组件。
     

    @Inject注解的使用方法
    @Inject注解的使用方法跟@Autowired也基本相似,但是需要注意
    1. 使用前需要导入jar包——javax.inject;
    2. 支持@Primary注解,而且因为没有精确匹配,@Primary的优先级最高;
    2. 不支持required=false,即不能注入null,如果找不到组件肯定报错;
    3. 默认按照属性名跟bean的名称匹配查找,如果不存在,再按类型匹配查找。
     
    例如,下面这容器中有一个EmployeeDao组件
    @Configuration
    public class InjectBeanConfig {
        @Bean(value = "employeeDao1")
        public EmployeeDao employeeDao1() {
            EmployeeDao employeeDao = new EmployeeDao();
            employeeDao.setLabel("1");
            return employeeDao;
        }
    }
    自动注入的方式如下
    @Inject
    private EmployeeDao employeeDao3;
    spring会先按属性名查找名称为employeDao3的组件,即applicationContext.getBean("employeeDao3"),结果不存在;
    然后按照类型查找,即applicationContext.getBean(EmployeDao.class),找到employeDao1组件,成功注入。
     
    如果容器中有多个同类型组件,例如
    @Configuration
    public class InjectBeanConfig {
        @Bean(value = "employeeDao1")
        public EmployeeDao employeeDao1() {
            EmployeeDao employeeDao = new EmployeeDao();
            employeeDao.setLabel("1");
            return employeeDao;
        }
        @Bean(value = "employeeDao2")
        public EmployeeDao employeeDao2() {
            EmployeeDao employeeDao = new EmployeeDao();
            employeeDao.setLabel("2");
            return employeeDao;
        }
        @Bean(value = "employeeDao3")
        public EmployeeDao employeeDao3() {
            EmployeeDao employeeDao = new EmployeeDao();
            employeeDao.setLabel("3");
            return employeeDao;
        }
    }
    注入方式还是这样
    @Inject
    private EmployeeDao employeeDao3;
    仍然会按属性名和bean的名称匹配,即applicationContext.getBean("employeeDao3"),找到employee3,成功注入。
     
    但是如果其中某个组件加了@Primary注解,会忽略属性名,优先注入,例如
    @Configuration
    public class InjectBeanConfig {
    @Bean(value
    = "employeeDao1") public EmployeeDao employeeDao1() { EmployeeDao employeeDao = new EmployeeDao(); employeeDao.setLabel("1"); return employeeDao; }
    @Bean(value
    = "employeeDao2") @Primary
    public EmployeeDao employeeDao2() { EmployeeDao employeeDao = new EmployeeDao(); employeeDao.setLabel("2"); return employeeDao; }
    @Bean(value
    = "employeeDao3") public EmployeeDao employeeDao3() { EmployeeDao employeeDao = new EmployeeDao(); employeeDao.setLabel("3"); return employeeDao; } }
    无论注入时使用什么样的属性名,都会注入employeeDao2。

  • 相关阅读:
    ASP.NET MVC 学习之路由(URL Routing)
    Linux 部署ASP.NET SQLite 应用 的坎坷之旅 附demo及源码
    linux解压zip文件
    /bin/sh^M:解释器错误:没有那个文件或目录
    mysql查看连接情况
    linux编译qt
    没有可用的软件包 xxx,但是它被其它的软件包引用了
    什么是人月
    qt linux 打包
    linux里安装使用svn
  • 原文地址:https://www.cnblogs.com/dubhlinn/p/10708142.html
Copyright © 2011-2022 走看看