浅谈spring DI 依赖注入方式和区别

目录
  • spring DI
  • 3种DI注解的区别
    • 1 @Autowired
    • 2 @Inject
    • 3 @Resource
  • 3种注入方式的区别
    • 1 field注入
    • 2 构造器注入
    • 3 setter注入
  • 构造器注入的好处
    • 1 依赖不可变
    • 2 依赖不为空
    • 3 完全初始化状态
    • 4 避免循环依赖
    • 5 总结

spring DI

Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反转)和AOP,平时使用最多的就是其中的IOC,我们通过将组件交由Spring的IOC容器管理,将对象的依赖关系由Spring控制,避免硬编码所造成的过度程序耦合。

3种DI注解的区别

1 @Autowired

使用特点

  • Autowired注解是spring框架提供的
  • Autowired注解优先byType获取java bean,其次byName
  • Autowired注解配合Qualifier注解区分java bean的名称,主要用于同一个类型的javabean有多个实
  • Autowired注解注入的对象,一般要求非null,如果允许为null,需要required=false属性声明
  • @Autowired可以作用在变量、setter方法、构造函数上

使用过程

a、 将@autowored写在被注入的成员变量上,就不用再xml文件中配置了,在程序中去掉相应的setter和getter方法,

b、 还可以写在构造方法上、setter方法上

c、@Qualifier
@Qualifier("XXX") 中的 XX是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。
不过需要注意的是@Autowired 可以对成员变量、方法以及构造函数进行注释,而 @Qualifier 的标注对象是成员变量、方法入参、构造函数入参。

2 @Inject

使用特点

  • @Inject是JSR330 (Dependency Injection for Java)中的规范,需要导入javax.inject.Inject; 实现注入
  • @Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named
  • @Inject可以作用在变量、setter方法、构造函数上
  • 与@Autowired使用类似,想比之下,采用spring提供的@Autowired更为普遍

使用过程
a、 将@Inject可以作用在变量、setter方法、构造函数上,和@Autowired一样

b、@Named
@Named("XXX") 中的 XX是 Bean 的名称,所以 @Inject和 @Named结合使用时,自动注入的策略就从 byType 转变成 byName 了。

3 @Resource

使用特点

  • esource注解是jdk提供的,属于j2ee规范
  • Resource注解优先byname获取java bean,其次byType
  • Resource注解的属性名称作为java bean的名称进行查找,如果有name参数,则使用name参数查找java bean
  • Resource注解如果声明了name属性,则必须按照name查找对象,不会再使用类型查找
  • @Resource可以作用在变量、setter方法上

使用过程
a、@Resource实例

3种注入方式的区别

注意项

  • 注入方式:field注入、setter注入与构造器注入
  • spring推荐使用setter方法和构造器注入Autowired的bean对象,因此IDEA等工具中私有属性使用Autowired注入会提示警告。setter方法和构造器注入的方式,可以让对象不依赖于spring而独立使用,更加灵活;私有属性则只能通过spring上下文自动注入,一旦注入失败,没有重新注入的方式。
  • @Resource不能用于构造器注入

1 field注入

@Controller
public class FooController {
  @Autowired
  //@Inject
  private FooService fooService;

  //简单的使用例子,下同
  public List<Foo> listFoo() {
      return fooService.list();
  }
}

这种注入方式应该是最常见的注入方式。原因很简单:

  • 注入方式简单:加入要注入的字段,附上@Autowired,即可完成。
  • 使得整体代码简洁明了,看起来美观大方。

2 构造器注入

@Controller
public class FooController {

  private final FooService fooService;

  @Autowired
  public FooController(FooService fooService) {
      this.fooService = fooService;
  }

  //使用方式上同,略
}

Spring4.x版本中推荐的注入方式,相较于field注入方式,就显得有点难看,特别是当注入的依赖很多(5个以上)的时候,就会明显的发现代码臃肿。
构造器注入的好处后面单独讨论。

3 setter注入

@Controller
public class FooController {

  private FooService fooService;

  //使用方式上同,略
  @Autowired
  public void setFooService(FooService fooService) {
      this.fooService = fooService;
  }
}

在Spring3.x刚推出的时候,推荐使用注入的就是这种,现在很少使用这种注解方式,写起来麻烦,当初推荐Spring自然也有他的道理: 构造器注入参数太多了,显得很笨重,另外setter的方式能用让类在之后重新配置或者重新注入。

构造器注入的好处

Spring在文档里怎么说:

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state.

简单的翻译一下:构造器注入的方式,能够保证注入的组件不可变,并且确保需要的依赖不为空。此外,构造器注入的依赖总是能够在返回客户端(组件)代码的时候保证完全初始化的状态。

1 依赖不可变

属性使用final关键字修饰

2 依赖不为空

(省去了我们对null的检查)
当要实例化类的时候,由于类已经实现了有参数的构造函数,所以不会调用默认构造函数,那么就需要Spring容器传入所需要的参数,所以就两种情况:1、有该类型的参数->传入,OK 。2:无该类型的参数->报错。所以保证不会为空,Spring不会传一个null进去
如果使用field注入,缺点显而易见,因为你不调用将一直无法发现NPE的存在。

3 完全初始化状态

这个可以跟上面的依赖不为空结合起来,向构造器传参之前,要确保注入的内容不为空,那么肯定要调用依赖组件的构造方法完成实例化。而在Java类加载实例化的过程中,构造方法是最后一步(之前如果有父类先初始化父类,然后自己的成员变量,最后才是构造方法)。所以返回来的都是初始化之后的状态。

4 避免循环依赖

使用field注入可能会导致循环依赖,即A里面注入B,B里面又注入A:

public class A {
    @Autowired
    private B b;
}
​
public class B {
    @Autowired
    private A a;
}

使用构造器注入,在spring项目启动的时候,就会抛出:BeanCurrentlyInCreationException:Requested bean is currently in creation: Is there an unresolvable circular reference?从而提醒你避免循环依赖;
如果是field注入的话,启动的时候不会报错,在使用那个bean的时候才会报错。

5 总结

  1. 保证依赖不可变(final关键字)
  2. 保证依赖不为空(省去了我们对其检查)
  3. 避免了循环依赖
  4. 当有一个依赖有多个实现的使用,推荐使用field注入或者setter注入的方式来指定注入的类型

Q1:跟3.x里说的一样,我要是有大量的依赖要注入,构造方法不会显得很臃肿吗?
对于这个问题,说明你的类当中有太多的责任,那么你要好好想一想是不是自己违反了类的单一性职责原则,从而导致有这么多的依赖要注入。
Q2:是不是其他的注入方式都不适合用了呢?
存在即是合理!setter的方式既然一开始被Spring推荐肯定是有它的道理,像之前提到的setter的方式能用让类在之后重新配置或者重新注入,就是其优点之一。除此之外,如果一个依赖有多种实现方式,我们可以使用@Qualifier,在构造方法里选择对应的名字注入,也可以使用field或者setter的方式来手动配置要注入的实现。

到此这篇关于浅谈spring DI 依赖注入方式和区别的文章就介绍到这了,更多相关spring DI 依赖注入内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解SpringBoot中实现依赖注入功能

    今天给大家介绍一下SpringBoot中是如何实现依赖注入的功能. 在以往spring使用中,依赖注入一般都是通过在Spring的配置文件中添加bean方法实现的,相对于这个方式SpringBoot的实现方式就显得非常便捷了.SpringBoot的实现方式基本都是通过注解实现的. 下面来看一下具体案例,这里我编写了三个测试类用于测试依赖注入到底是否可以正确实现. TestBiz接口: package example.biz; public interface TestBiz { public S

  • 详析Spring中依赖注入的三种方式

    前言 平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中.依赖注入的另一种说法是"控制反转",通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员,而控制反转是指new实例工作不由我们程序员来做而是交给spring容器来做. 在Sprin

  • Spring 依赖注入的几种方式详解

    IoC 简介 平常的Java开发中,程序员在某个类中需要依赖其它类的方法. 通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理. Spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过Spring容器帮我们new指定实例并且将实例注入到需要该对象的类中. 依赖注入的另一种说法是"控制反转".通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员. 而控制反转是指new实例工作不由我们程序员来做而是交给Spring容器来做.

  • 详解Java Spring各种依赖注入注解的区别

    注解注入顾名思义就是通过注解来实现注入,Spring和注入相关的常见注解有Autowired.Resource.Qualifier.Service.Controller.Repository.Component. Autowired是自动注入,自动从spring的上下文找到合适的bean来注入 Resource用来指定名称注入 Qualifier和Autowired配合使用,指定bean的名称 Service,Controller,Repository分别标记类是Service层类,Contro

  • Spring依赖注入的两种方式(根据实例详解)

    1,Set注入    2,构造注入 Set方法注入: 原理:通过类的setter方法完成依赖关系的设置 name属性的取值依setter方法名而定,要求这个类里面这个对应的属性必须有setter方法. Set方法注入时spring中配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans&qu

  • spring四种依赖注入方式的详细介绍

    平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中.依赖注入的另一种说法是"控制反转",通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员,而控制反转是指new实例工作不由我们程序员来做而是交给spring容器来做. spring有多种

  • 浅谈Spring IoC容器的依赖注入原理

    本文介绍了浅谈Spring IoC容器的依赖注入原理,分享给大家,具体如下: IoC容器初始化的过程,主要完成的工作是在IoC容器中建立 BeanDefinition 数据映射,并没有看到IoC容器对Bean依赖关系进行注入, 假设当前IoC容器已经载入用户定义的Bean信息,依赖注入主要发生在两个阶段 正常情况下,由用户第一次向IoC容器索要Bean时触发 但我们可以在 BeanDefinition 信息中通过控制 lazy-init 属性来让容器完成对Bean的预实例化,即在初始化的过程中就

  • Spring bean的实例化和IOC依赖注入详解

    前言 我们知道,IOC是Spring的核心.它来负责控制对象的生命周期和对象间的关系. 举个例子,我们如何来找对象的呢?常见的情况是,在路上要到处去看哪个MM既漂亮身材又好,符合我们的口味.就打听她们的电话号码,制造关联想办法认识她们,然后...这里省略N步,最后谈恋爱结婚. IOC在这里就像婚介所,里面有很多适婚男女的资料,如果你有需求,直接告诉它你需要个什么样的女朋友就好了.它会给我们提供一个MM,直接谈恋爱结婚,完美! 下面就来看Spring是如何生成并管理这些对象的呢? 1.方法入口 o

  • 浅谈spring DI 依赖注入方式和区别

    目录 spring DI 3种DI注解的区别 1 @Autowired 2 @Inject 3 @Resource 3种注入方式的区别 1 field注入 2 构造器注入 3 setter注入 构造器注入的好处 1 依赖不可变 2 依赖不为空 3 完全初始化状态 4 避免循环依赖 5 总结 spring DI Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反转)和AOP,平时使用最多的就是其中的IOC,我们通过将组件交由Sp

  • 浅谈spring ioc的注入方式及注入不同的数据类型

    关于Spring-IoC的简单使用参考: spring ioc的简单实例及bean的作用域属性解析 1.通过set方法注入不同数据类型 测试类代码(set方式注入的属性一定要加set方法) /**通过set方法注入示例*/ public class IoC_By_Set { /**注入Integer类型参数*/ private Integer id; /**注入String类型参数*/ private String name; /**注入实体Bean*/ private User user; /

  • 浅谈Spring Context加载方式

    Spring 加载方式 对于可执行文件方式,我们一般的加载Spring 配置的方式是 ClassPathXmlApplicationContext public static void main(String[] args) { ClassPathXmlApplicationContext xmlApplicationContext = new ClassPathXmlApplicationContext("classpath:spring-context.xml"); DemoSer

  • 浅谈Spring中几个PostProcessor的区别与联系

    目录 Spring几个PostProcessor的区别 首先明确 Bean 的生命周期: 查看 IOC 容器创建时的调用流程 spring-postProcessor的执行时机 BeanPostProcessor: postProcessAfterInitialization调用时机: InstantiationAwareBeanPostProcessor 总结: 执行顺序 Spring几个PostProcessor的区别 首先明确 Bean 的生命周期: 首先注册 Bean 的定义信息: 然后

  • Spring框架中IoC容器与DI依赖注入教程

    目录 一.Spring 是什么 1.1 什么是容器 1.2 什么是 IoC 二.理解 IoC 2.1 传统程序开发的问题 2.2 分析 2.3 控制反转式程序开发 2.4 对比总结规律 2.5 理解 Spring IoC 三.DI 概念说明 四.总结 一.Spring 是什么 我们通常所说的 Spring 指的是 Spring Framework (Spring 框架),它是⼀个开源框架,有着活跃而庞大的社区,这就是它之所以能长久不衰的原因.Spring ⽀持⼴泛的应⽤场景,它可以让 Java

  • 浅谈Spring的两种事务定义方式

    一.声明式 这种方法不需要对原有的业务做任何修改,通过在XML文件中定义需要拦截方法的匹配即可完成配置,要求是,业务处理中的方法的命名要有规律,比如setXxx,xxxUpdate等等.详细配置如下: <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="

  • 浅谈Spring 解决循环依赖必须要三级缓存吗

    我们都知道 Spring 是通过三级缓存来解决循环依赖的,但是解决循环依赖真的需要使用到三级缓冲吗?只使用两级缓存是否可以呢?本篇文章就 Spring 是如何使用三级缓存解决循环依赖作为引子,验证两级缓存是否可以解决循环依赖. 循环依赖 既然要解决循环依赖,那么就要知道循环依赖是什么.如下图所示: 通过上图,我们可以看出: A 依赖于 B B 依赖于 C C 依赖于 A public class A { private B b; } public class B { private C c; }

随机推荐