详解Spring中接口的bean是如何注入的

Question:

这个问题困扰了我好久,一直疑问这个接口的bean是怎么注入进去的?因为只看到使用@Service注入了实现类serviceImpl,使用时怎么能获取的接口,而且还能调用到实现类的方法,难道这个接口是在什么时候自动注入了进去,且和实现类关联上了?

接口

public interface TestService {
  public String test();
}

实现类impl

@Service
public class TestServiceImpl implements TestService {
  @Override
  public String test() {
    return "TestServiceImpl";
  }
}

Controller的调用:

@RestController
public class TestCtl {
  @Autowired
  private TestService testService;

  @RequestMapping("/test")
  public String test() {
    return testService.test();
  }
}

请求结果:

Answwer:

后来才知道,并没有注入接口的bean,只注入了实现类serviceImpl的bean,接口只是用来接收的。

这里就要说到@Autowired/@Resource的注入原理了:@Autowired是Spring的注解,Autowired默认先按byType,如果发现找到多个bean,则,又按照byName方式比对,如果还有多个,则报出异常;@Resource 是JDK1.6支持的注解,默认按照名称(Byname)进行装配, 如果没有指定name属性,当注解写在字段上时,默认取字段名,按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

再来说Controller获取实例的过程:使用@Autowired,程序在spring的容器中查找类型是TestService的bean,刚好找到有且只有一个此类型的bean,即testServiceImpl,所以就把testServiceImpl自动装配到了controller的实例testService中,testService其实就是TestServiceImpl实现类;

如果使用的是@Resource,则是先在容器中查找名字为testService的bean,但并没有找到,因为容器中的bean名字是TestServiceImpl(如果@Service没指定bean的value属性,则注入bean的名字就是类名,如果指定了则是指定的名字),然后再通过类型查找TestService类型的bean,找到唯一的了个TestService类型bean(即TestServiceImpl),所以就自动装配实例成功了。更多面试题,欢迎关注公众号Java面试题精选

Note:

byName 通过参数名 自动装配,如果一个bean的name 和另外一个bean的 property 相同,就自动装配。

byType 通过参数的数据类型自动自动装配,如果一个bean的数据类型和另外一个bean的property属性的数据类型兼容,就自动装配

效率上来说@Autowired/@Resource差不多,不过推荐使用@Resource一点,因为当接口有多个实现时@Resource直接就能通过name属性来指定实现类,而@Autowired还要结合@Qualifier注解来使用,且@Resource是jdk的注释,可与Spring解耦。

Question:

如果一个接口有多个实现类时,通过注解获取实例时怎么知道应该获取的是哪一个实现类serviceImpl呢?

再增加了一个实现类TestServiceImpl2

@Service
public class TestServiceImpl2 implements TestService {
  @Override
  public String test() {
    return "TestServiceImpl2";
  }
}

Answer:

多个实现类的话可通过以下2种方式来指定具体要使用哪一个实现:

1、 通过指定bean的名字来明确到底要实例哪一个类

@Autowired 需要结合@Qualifier来使用,如下:

@Autowired
@Qualifier("testServiceImpl")
private TestService testService;

@Resource可直接通过指定name属性的值即可,不过也可以使用@Qualifier(有点多此一举了…)

@Resource(name = "testServiceImpl")
private TestService testService;  

@Resource如果不显示的指定name值,就会自动把实例变量的名称作为name的值的,所以也可以直接这样写:

@Resource
private TestService testServiceImpl;

2、 通过在实现类上添加@Primary注解来指定默认加载类

@Service
@Primary
public class TestServiceImpl2 implements TestService {
  @Override
  public String test() {
    return "TestServiceImpl2";
  }
}

这样如果在使用@Autowired/@Resource获取实例时如果不指定bean的名字,就会默认获取TestServiceImpl2的bean,如果指定了bean的名字则以指定的为准。

Question:

为什么非要调用接口来多此一举,而不直接调用实现类serviceImpl的bean来得简单明了呢?

Answer:

1、 直接获取实现类serviceImpl的bean也是可以的;

2、 至于加一层接口的原因:一是AOP程序设置思想指导,给别人调用的接口,调用者只想知道方法和功能,而对于这个方法内部逻辑怎么实现的并不关心;二是可以降低各个模块间的关联,实现松耦合、程序分层、高扩展性,使程序更加灵活,他除了在规范上有卓越贡献外,最精髓的是在多态上的运用;继承只能单一继承,接口却可以多实现

3、 当业务逻辑简单,变更较少,项目自用时,省略掉接口直接使用实现类更简单明了;反之则推荐使用接口;

总结

到此这篇关于详解Spring中接口的bean是如何注入的文章就介绍到这了,更多相关Spring接口的bean注入内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java的Spring框架中bean的继承与内部bean的注入

    bean的定义继承 bean定义可以包含很多的配置信息,包括构造函数的参数,属性值,比如初始化方法,静态工厂方法名等容器的具体信息. 子bean定义从父定义继承配置数据.子的定义可以覆盖一些值,或者根据需要添加其他. Spring bean定义继承无关,与Java类的继承,但继承的概念是一样的.你可以定义一个父bean定义为模板和其他孩子bean可以从父bean继承所需的配置. 当使用基于XML的配置元数据,指明一个子bean定义使用所在的当前属性指定的父bean作为这个属性的值. 例如: 让我

  • Spring中如何动态注入Bean实例教程

    前言 在Spring中提供了非常多的方式注入实例,但是由于在初始化顺序的不同,基于标注的注入方式,容易出现未被正确注入成功的情况. 本文将介绍一种在实际项目中基于动态的方式来提取Spring管理的Bean. 下面话不多说了,来一起看看详细的介绍吧. 一.基于标注的方式注入实例 需要在Bean初始化之时,其依赖的对象必须初始化完毕.如果被注入的对象初始化晚于当前对象,则注入的对象将为null. 1.1 @Autowired 按照类型来加载Spring管理的Bean.默认情况下要求其Bean必须存在

  • Spring boot将配置属性注入到bean类中

    一.@ConfigurationProperties注解的使用 看配置文件,我的是yaml格式的配置: // file application.yml my: servers: - dev.bar.com - foo.bar.com - jiaobuchong.com 下面我要将上面的配置属性注入到一个Java Bean类中,看码: import org.springframework.boot.context.properties.ConfigurationProperties; import

  • 关于SpringBoot获取IOC容器中注入的Bean(推荐)

    一: 注入一个TestUtils类 package com.shop.sell.Utils; import com.shop.sell.dto.CartDTO; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class TestUtils { @Bean(name="test

  • 详解Spring中bean的几种注入方式

    首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入.依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖. Spring容器中支持的依赖注入方式主要有属性注入.构造函数注入.工厂方法注入.接下来将为大家详细介绍这三种依赖注入的方式以及它们的具体配置方法. 1.属性注入 属性注入即通过setXXX( )方法注入bean的属性值或依赖对象.由于属性注入方式具有可选择性和灵活性高的特点,因此它也是实际开发中最常用的注入方式

  • Spring 多线程下注入bean问题详解

    本文介绍了Spring 多线程下注入bean问题详解,分享给大家,具体如下: 问题 Spring中多线程注入userThreadService注不进去,显示userThreadService为null异常 代码如下: public class UserThreadTask implements Runnable { @Autowired private UserThreadService userThreadService; @Override public void run() { AdeUs

  • Spring Bean三种注入方式详解

    在Spring容器中为一个bean配置依赖注入有三种方式: 使用属性的setter方法注入  这是最常用的方式: 使用构造器注入: 使用Filed注入(用于注解方式). Field注入是最常见的一种方式,可以采用 @Autowired 对Bean类的接口进行初始化,代码如下 @ContextConfiguration({"/META-INF/spring/amazing-base.xml"}) @RunWith(SpringJUnit4ClassRunner.class) public

  • spring中通过ApplicationContext getBean获取注入对象的方法实例

    用SpringContextUtil实现ApplicationContextAware package util; import java.util.Locale; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; pub

  • 详解Java的Spring框架中bean的注入集合

    使用value属性和使用<property>标签的ref属性在你的bean配置文件中的对象引用,这两种情况下可以处理单值到一个bean,如果你想通过多元值,如Java Collection类型List, Set, Map 及 Properties.要处理这种情况,Spring提供了四种类型的如下集合的配置元素: 可以使用<list> 或<set> 来连接任何实现java.util.Collection或数组. 会遇到两种情况(a)将收集的直接的值及(b)传递一个bean

  • Spring循环依赖正确性及Bean注入的顺序关系详解

    一.前言 我们知道 Spring 可以是懒加载的,就是当真正使用到 Bean 的时候才实例化 Bean.当然也不全是这样,例如配置 Bean 的 lazy-init 属性,可以控制 Spring 的加载时机.现在机器的性能.内存等都比较高,基本上也不使用懒加载,在容器启动时候来加载bean,启动时间稍微长一点儿,这样在实际获取 bean 供业务使用时,就可以减轻不少负担,这个后面再做分析. 我们使用到 Bean 的时候,最直接的方式就是从 Factroy 中获取,这个就是加载 Bean 实例的源

随机推荐