Spring IoC全注解开发-依赖注入

网友投稿 542 2022-11-01

Spring IoC全注解开发-依赖注入

Spring IoC全注解开发-依赖注入

本章的开始讲述了Spring IoC的两个作用,上一节只讨论了将Bean装配到IoC容器中,对于如何进行获取,还有一个作用没有谈及,那就是Bean之间的依赖。在Spring IoC容器中,我们称之为依赖注入(Dependency Injection, DI).

例如,人类(Persion)有时候利用一些动物(Animal)去完成一些事情,比方说狗(Dog)用来看门,猫(cat)用来抓老鼠。。。于是一些事情就依赖于那些可爱的动物了,如图。

为了更好的展示这个过程,首先定义两个接口,一个是人类(Persion)另一个是动物(Animal)。人类通过动物去提供一些特殊服务

定义人和动物接口

package cn.hctech2006.boot.bootall.bean;/** * 人类接口 */public interface Person { //使用动物服务 public void servie(); //设置动物 public void setAnimanl(Animal animanl);}

package cn.hctech2006.boot.bootall.bean;/** * 动物接口 */public interface Animal { public void use();}

两个实现类

package cn.hctech2006.boot.bootall.bean;import org.springframework.beans.factory.annotation.Autowired;/** * 人的实现类 */ @Componentpublic class BussinessPersion implements Person { @Autowired private Animal animal = null; @Override public void servie() { this.animal.use(); } @Override public void setAnimanl(Animal animanl) { this.animal=animanl; }}

package cn.hctech2006.boot.bootall.bean;/** * 动物实现类 */ @Componentpublic class Dog implements Animal { @Override public void use() { System.out.println("狗["+Dog.class.getSimpleName()+"]是看门用的。"); }}

暂时不扫描

package cn.hctech2006.boot.bootall.bean;/** * 动物实现类 */public class Cat implements Animal { @Override public void use() { System.out.println("猫["+Cat.class.getSimpleName()+"]是抓老鼠用的。"); }}

这里应该注意加粗的注解@Autowired,这是我们在Spring里面最常用的注解之一,十分重要,他会根据属性的类型(by type)找到对应的Bean进行注入。这里的Dog类是动物的一种,所以Spring IoC容器会把Dog的实例注入BussinessPersion中。这样通过Spring IoC容器获取BussinessPersion实例的时候就能够使用Dog实例来提供服务了,下面是测试代码

显然测试成功,这个时候Spring IoC容器已经通过注解@AutoWired成功的将dog注入到了BussinessPersion实例当中,但是这只是一个比较简单的例子,我们有必要继续探讨@Autowired

注解@Autowired@Autowired注解注入的机制最基本的一条是根据类型(by type),我们回顾IoC容器的顶级接口BeanFactory,就可以知道IoC容器是通过getBean方法获取对应的Bean,而getBean方法又支持支持根据类型(by type)和根据名称(by name)。在回到上面的例子,我们只是创建了一个动物-狗,而实际上动物还有猫等,猫可以抓老鼠,于是我们又创建一个猫类

/**

动物实现类*/@Componentpublic class Cat implements Animal {@Overridepublic void use() {System.out.println(“猫[”+Cat.class.getSimpleName()+"]是抓老鼠用的。");}}如果我们继续使用之前的BussinessPerson类,那么麻烦来了,因为这个类只是定义了一个动物属性(Animal),而我们确实有两个动物,一个狗,一个猫,Spring IoC如何注入呢?如果你还进行测试,很快你就可以看到IoC容器抛出异常,如下面日志所示:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'cn.hctech2006.boot.bootall.bean.Animal'

从日志可以看出,SPring IoC容器并不知道你需要注入什么动物(是狗?是猫?)给BussinessPersion类对象,从而引发错误的产生。那么@Autowired能处理这个问题吗? 答案是肯定的。假设我们现在需要的是狗提供服务,那么可以把属性的名称转换为dog,也就是原来的

= null;

改为

= null;

再次测试会发现是狗在提供服务 因为@Autowired提供这样的规则,首先他会根据类型找到对应的Bean,如果对应类型的Bean不是唯一的,那么他会根据其属性名称和Bean的名称进行匹配。如果匹配得上,就使用该Bean,如果还是无法匹配就会报异常。 需要注意的是@Autowired是一个默认必须找到对应Bean的注解,如果不能确定其标注属性一定存在并且允许这个被标注的属性为null,那么你可以设置@Autowired属性required为false,例如向下面一样

=false)

同样,他除了可以标注属性外还可以标注方法,如setAnimal方法,如下

(Animal animanl) { this.animal=animanl; }}

这样他也会使用setAnimal方法从IoC容器中找到对应的动物进行注入,甚至可以用在方法的参数上,后面会再谈到他。 2. 消除歧义性-@Primary和@Quelifier 在上面我们发现有狗有猫的时候,为了能够继续使用@Autowired,我们做了一个决定,将BuinessPerson的属性名称从animal改成了dog。显然这是一种憋屈的做法。好好一个动物却被我们定义成了狗。产生注入失败问题的根本是按照类型(by type)查找,正如动物卡哇伊有多个类型,这样就会造成Spring IoC容器注入的困扰,我们把这一个问题成为歧义性。知道这个原因之后,那么这两个注解是从哪一个是从哪个角度去解决这些问题的呢?这就是本节要解决的问题。 首先是一个注解@Primary,他是一个修改优权的注解,当我们有猫有狗的时候,假设这次需要使用猫,那么需要在猫类的定义上加上@Primary注解就可以了,类似下面:

/** * 动物实现类 */@Primary@Componentpublic class Dog implements Animal { @Override public void use() { System.out.println("狗["+Dog.class.getSimpleName()+"]是看门用的。"); }}

这里的Primary的含义告诉Spring IoC容器,当发现有多个同样类型的Bean时,请优先使用我进行注入,于是再次发现狗为你提供服务。因为当Spring进行注入的时候,虽然他发现存在多个动物,但是因为cat被标注为@Primary,所以优先采用Dog实例进行注入,这样就通过优先级的变化使得IoC容器知道注入那个具体的实例来满足依赖注入。 然后,有时候@Primary也可以使用在多个类上,也许无论猫狗都可以带上@Primary注解,其结果是IoC容器还是无法区分采用那个Bean的实例进行注入,又或者说我们需要更加灵活的机制来实现注入,那么@Quelifier可以满足你的愿望。他的字符串value需要一个字符串去定义,他将与@Autowired组合在一起,通过类型和名称一起找到Bean。我们知道Bean的名称在Spring IoC容器是唯一标识。通过这个就可以消除歧义性了。此时你是否想起BeanFactory接口中的这个方法呢?

T getBean(String name, Class requiredType) throws BeansException;

通过它既可以按照名称和类型的组合找到对象了。下面假设狗已经标注了@Primary,而我们需要猫提供服务,因此需要修改BussinessPerson属性animal的标注以适合我们的需要,如下所示:

("cat") @Autowired private Animal animal = null;

猫[Cat]是抓老鼠用的。

带有参数的构造方法在上面,我们都是基于一个默认的情况,那就是不带参数的构造方法实现依赖注入。但是事实上,有些类只有带有参数的构造方法,于是上述的方法就不能使用了。为了满足这个功能,我们可以使用@Autowired注解对构造方法的参数进行注入,例如,修改类BussinessPersion来满足这个功能。代码如下

package cn.hctech2006.boot.bootall.bean;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Component;/** * 人的实现类 */@Componentpublic class BussinessPersion implements Person { private Animal animal = null; public BussinessPersion(@Autowired @Qualifier("cat") Animal animal) { this.animal = animal; } @Override public void servie() { this.animal.use(); } @Override public void setAnimanl(Animal animanl) { this.animal=animanl; }}

可以看到,代码中取消了@Autowired对属性和方法的标注。在构造方法的参数加上了@Autowired和@Qulifier注解,使得他们能够注入进来。这里是用@Qulifier是为了避免歧义性。当然如果只有一种动物,直接使用@Autowired即可

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring Boot全局异常处理
下一篇:ezrpc 是一个微服务框架,用于服务器端的 RPC 通讯
相关文章

 发表评论

暂时没有评论,来抢沙发吧~