上一篇文章,咱们聊了与 Bean 的申明相干的内容,本文,咱们重点聊聊与 Bean 注入相干的内容。

注入形式

Bean 注入的形式,次要蕴含三种,即:构造函数注入、setter 注入和属性注入。

构造函数注入

构造函数注入,示例代码如下。对于上面的代码,利用启动后,myBean 属性会被顺利注入:

@Componentpublic class InjectionComponent {    private MyBean myBean;    public InjectionComponent(MyBean myBean) {        this.myBean = myBean;    }}

setter 注入

setter 注入的示例代码如下(必须给 setter 办法增加 @Autowired 注解):

@Componentpublic class InjectionComponent2 {    private MyBean myBean;    @Autowired    public void setMyBean(MyBean myBean) {        this.myBean = myBean;    }}

属性注入

属性注入的示例代码如下:

@Componentpublic class InjectionComponent3 {    @Autowired    private MyBean myBean;}

申明注解

@Autowired

从下面的代码例子,咱们能够晓得 @Autowired 是用来申明 Bean 的注入的。

@Autowired 的作用指标

@Autowired 是 JSR-330 javax.inject.Inject 的代替计划,能够作用在构造函数、办法、参数、字段和注解上。

作用在构造函数上
  • 如下面的例子 构造函数注入,应用该形式进行注入时,@Autowired 不是必须的。
  • 构造函数能够是公共的,也能够是公有的。
  • 构造函数中的参数,必须在 Spring IoC 容器中能够找到,否则利用启动时将抛出异样。
  • 如果存在多个构造函数,则必须存在一个无参构造函数,否则利用启动时将抛出异样。如果存在无参构造函数,则创立实例时,将应用该构造函数进行创立。
  • 当存在多个构造函数时,如果在其中一个构造函数上加上 @Autowired,则下面一条规定会被突破,即此时能够不存在无参构造函数,且创立实例时,应用的不是无参构造函数,而是加上了 @Autowired 的构造函数。
  • @Autowired 有一个 required 属性,默认为 true,示意构造函数中的全副参数都必须在 Spring IoC 容器中存在,否则利用启动时将抛出异样。
  • 默认状况下,不能有多个构造函数存在 @Autowired 注解,否则,利用启动时将抛出异样。
  • 如果多个构造函数都加上 @Autowired 注解,那么,这些注解的 required 属性必须全都设置为 false。这种状况下,示意这几个构造函数都是候选构造函数,创立实例时,将抉择可能满足的参数最多的一个构造函数来进行对象的创立。在这根底上,会优先选择公共的构造函数。例如:如果存在一个蕴含 2 个参数和一个蕴含 3 个参数的构造函数,且这两个构造函数都可能被满足,然而蕴含 2 个参数的构造函数是公共的,蕴含 3 个参数的构造函数是公有的,那么,此时抉择的将是蕴含 2 个参数的构造函数。
  • 如果下面一条规定中的所有候选构造函数,没有一个能够被满足,并且存在无参构造函数,则创立实例时会抉择无参构造函数。如果此时不存在无参构造函数,则利用启动时将抛出异样。

如上面的代码,因为不存在 Cache 类的实例,而 MyBean 类和 RestTemplate 类的实例是存在的,因而,利用启动时将应用构造函数 InjectionComponent4(MyBean, RestTemplate) 来初始化 InjectionComponent4 的实例。

@Componentpublic class InjectionComponent4 {    private MyBean myBean;    private RestTemplate restTemplate;    private Cache cache;    @Autowired(required = false)    public InjectionComponent4(MyBean myBean) {        this.myBean = myBean;    }    @Autowired(required = false)    public InjectionComponent4(MyBean myBean, RestTemplate restTemplate) {        this.myBean = myBean;        this.restTemplate = restTemplate;    }    @Autowired(required = false)    public InjectionComponent4(MyBean myBean, RestTemplate restTemplate, Cache cache) {        this.myBean = myBean;        this.restTemplate = restTemplate;        this.cache = cache;    }}
作用在办法上

当 @Autowired 作用在某个办法时,该办法能够有任意的名称和任意数量的参数,setter 办法只是其中的一种非凡模式,该办法也能够是公有的:

@Componentpublic class InjectionComponent5 {    private MyBean myBean;    @Autowired    private void myBean(MyBean myBean) {        this.myBean = myBean;    }}
作用在参数上

尽管 Spring 框架 5.0 之后反对在构造函数和办法的参数上加上 @Autowired 注解,然而 Spring 框架中的大部分代码都不反对该形式的注入,目前只有 Spring Test 局部反对。如上面的代码,在理论运行的时候,myBean 是注入不了的:

@Componentpublic class InjectionComponent6 {    private MyBean myBean;    public void init(@Autowired MyBean myBean) {        this.myBean = myBean;    }}
作用在字段上

示例见前文的 属性注入

Collection 和 Map 的注入

应用 @Autowire 还能够注入 Collection 和 Map 类型的变量。

Collection 的注入

如上面的代码,OrderBean 和 OrderBean2 的实例都会被注入到 InjectionComponent7 的 orderBeans 中,能够通过实现 Ordered 接口为类的实例提供排序功能,order 小的排在后面。

@Componentpublic class OrderBean extends BaseOrderBean implements Ordered {    @Override    public int getOrder() {        return 1;    }}
@Componentpublic class OrderBean2 extends BaseOrderBean implements Ordered {    @Override    public int getOrder() {        return 2;    }}
@Componentpublic class InjectionComponent7 {    @Autowired    private List<BaseOrderBean> orderBeans;}

也能够通过 @Order 实现排序:

public class OrderBean3 {    private String field;    public void setField(String field) {        this.field = field;    }}
@Configurationpublic class BeanConfig {    @Bean    @Order(1)    public OrderBean3 orderBean3() {        OrderBean3 orderBean = new OrderBean3();        orderBean.setField("order 1");        return orderBean;    }    @Bean    @Order(2)    public OrderBean3 orderBean4() {        OrderBean3 orderBean = new OrderBean3();        orderBean.setField("order 2");        return orderBean;    }}
@Componentpublic class InjectionComponent8 {    @Autowired    private List<OrderBean3> orderBeans;}
Map 的注入

上面的代码中,全副 BaseOrderBean 的实例都会注入到 orderBeanMap 中,Bean 的名字将作为 Map 的键,Bean 的实例将作为 Map 的值。

@Componentpublic class InjectionComponent9 {    @Autowired    private Map<String, BaseOrderBean> orderBeanMap;}

@Primary

@Autowired 依据 Bean 的类型找到它,并将它注入到变量中,如果一个类型有两个 Bean,那么注入的时候将不晓得要注入的是哪一个。如果用 @Primary 对 Bean 进行了标注,那么注入的时候就会抉择该 Bean 进行注入。

public class MyBean3 {    private String field;    public MyBean3(String field) {        this.field = field;    }}
@Configurationpublic class BeanConfig2 {    @Primary    @Bean    public MyBean3 primaryTestBean1() {        return new MyBean3("primaryTestBean1");    }    @Bean    public MyBean3 primaryTestBean2() {        return new MyBean3("primaryTestBean2");    }}
@Componentpublic class InjectionComponent10 {    @Autowired    private MyBean3 myBean;}

@Qualifier

一个类型有多个 Bean 的时候,也能够通过 @Qualifier 进行标注,以让变量注入的时候依据 Bean 的名字找到 Bean。

@Configurationpublic class BeanConfig3 {    @Bean    public MyBean3 qualifierTestBean1() {        return new MyBean3("qualifierTestBean1");    }    @Bean    public MyBean3 qualifierTestBean2() {        return new MyBean3("qualifierTestBean2");    }}
@Componentpublic class InjectionComponent11 {    @Qualifier("qualifierTestBean1")    @Autowired    private MyBean3 myBean;}

@Qualifier 还有另一个用法,就是在申明 Bean 和注入 Bean 的中央都应用该注解进行标注,那么注入的时候就会主动定位到对应的 Bean。

@Configurationpublic class BeanConfig4 {    @Qualifier    @Bean    public MyBean3 qualifierTestBean3() {        return new MyBean3("qualifierTestBean3");    }    @Bean    public MyBean3 qualifierTestBean4() {        return new MyBean3("qualifierTestBean4");    }}
@Componentpublic class InjectionComponent12 {    @Qualifier    @Autowired    private MyBean3 myBean;}

@Resource

@Resource 也是用来申明 Bean 注入的注解。

  • 对于 @Resource,默认状况下,优先应用名字查找待注入的 Bean;如果找不到,则应用类型查找待注入的 Bean。
  • @Resource 能够正文在办法和字段上。
  • 正文在办法上时,Bean 类型为办法参数的类型,Bean 名字优先应用办法的名字(如果是 setter 办法,会去掉 “set”,并将首字母小写),如果通过办法名字找不到 Bean,则再应用参数的名字。
  • 正文在字段上时,Bean 类型为字段类型,Bean 名字为字段名字。

代码示例如下:

public class ResourceBean {    private String field;    public ResourceBean(String field) {        this.field = field;    }}
@Configurationpublic class BeanConfig5 {    @Bean    public ResourceBean resourceBean1() {        return new ResourceBean("resourceBean1");    }    @Bean    public ResourceBean resourceBean2() {        return new ResourceBean("resourceBean2");    }}
@Componentpublic class InjectionComponent13 {    @Resource    private ResourceBean resourceBean1;    private ResourceBean resourceBean2;    @Resource    public void setResourceBean2(ResourceBean resourceBean) {        this.resourceBean2 = resourceBean;    }}

@Resource 有一个 name 属性,能够间接指定 Bean 的名字:

@Componentpublic class InjectionComponent14 {    @Resource(name = "resourceBean1")    private ResourceBean myBean1;    private ResourceBean myBean2;    @Resource(name = "resourceBean2")    public void setMyBean2(ResourceBean resourceBean) {        this.myBean2 = resourceBean;    }}

另外,@Resource 也能够配合 @Primary 或 @Qualifier 一起应用。

@Inject

要应用 @Inject,须要先引入 jar 包:

<dependency>    <groupId>javax.inject</groupId>    <artifactId>javax.inject</artifactId>    <version>1</version></dependency>

@Inject 能够正文在构造函数、办法和字段上,@Inject 能够通过类型注入:

@Componentpublic class InjectionComponent15 {    @Inject    private MyBean myBean1;    private MyBean myBean2;    @Inject    public void setMyBean(MyBean myBean) {        this.myBean2 = myBean;    }    private MyBean myBean3;    @Inject    public InjectionComponent15(MyBean myBean) {        this.myBean3 = myBean;    }}

@Inject 也能够通过名字注入:

@Componentpublic class InjectionComponent16 {    @Inject    private ResourceBean resourceBean1;    private ResourceBean resourceBean2;    @Inject    public void setResourceBean(ResourceBean resourceBean2) {        this.resourceBean2 = resourceBean2;    }    private ResourceBean resourceBean3;    @Inject    public InjectionComponent16(ResourceBean resourceBean2) {        this.resourceBean3 = resourceBean2;    }}

同样地,@Inject 也能够配合 @Primary 或 @Qualifier 一起应用。

小结

@Autowired、@Resource、@Inject 有什么异同点?显然,它们都能够用来申明 Bean 的注入。它们的不同点次要集中在:1. 能够标注的中央有所差别,2. 领有的属性不同,3. 注入的形式略有差别。而它们最大的不同,笔者认为是,@Autowired 是 Spring 自定义的注解(@Primary、@Qualifier 也是 Spring 自定义的注解),@Resource 是 Jakarta 定义的注解,而 @Inject 则是在 JSR-330 中定义的注解,即它们的作用十分相似,最大的区别在于制定者的不同。