Spring Boot中的依赖注入和自动注入

news/2024/11/7 21:06:15/

Spring Boot中的依赖注入和自动注入

  • 前言
  • 详细讲讲依赖注入
  • 给出依赖的三种注入的方式的示例
  • 从概念上讲讲自动注入
  • Spring Boot中注解@Autowired,自动注入注解默认使用哪种注入方式
  • 给我一些上面自动注入的简单示例
  • 依赖注入和自动注入的关联以及不同点

前言

以下内容为本人学习Spring Boot的依赖注入和自动注入与ChatGpt提问后对其回答进行部分修改(有的错误实在是离谱 = =)、格式调整等操作后的答案,可能对于其中部分细节(是错是对,能力有限有的看不出来 = =),并未做深入探究,大家感兴趣的话可以自行验证。

详细讲讲依赖注入

依赖注入Dependency Injection,简称DI)的概念最早由Martin Fowler2004年提出。依赖注入是一种软件设计模式,旨在解耦和组织对象之间的依赖关系,以提高代码的可维护性和可测试性

在传统的编程模式中,一个对象通常负责自己创建和管理所依赖的其他对象。这种紧密耦合的设计模式会导致代码的脆弱性,因为对象需要直接知道它所依赖的对象的实现细节,并且对于变化会很敏感(使用过传统编程模式的应该深有体会)。此外,这也会增加代码的复杂性,使得对象之间的关系变得难以理解和维护

依赖注入的目标是通过将依赖对象的创建和管理责任从对象本身转移到外部容器中,以实现松耦合和可维护。在依赖注入中,对象声明它所需要的依赖关系,而不需要关心如何创建或获取这些依赖对象。

依赖注入的核心思想是控制反转Inversion of Control,简称IoC)。在传统的编程模式中,对象自己控制创建和管理它所依赖的对象,而在依赖注入中,这种控制被反转了。对象不再自己创建依赖对象,而是通过外部容器(通常是一个IoC容器)来创建和注入依赖对象

依赖注入可以通过以下几种方式实现

  1. 构造函数注入(Constructor Injection):对象通过构造函数接收依赖对象作为参数。在创建对象时,依赖对象会被传递给构造函数进行注入。这种方式通常提供了更好的不变性和一致性

  2. Setter方法注入(Setter Injection):对象通过Setter方法设置依赖对象。在对象创建后,通过调用相应的Setter方法来注入依赖对象。这种方式可以提供更灵活的注入方式,允许依赖对象在对象创建后被替换

  3. 接口注入(Interface Injection):对象通过实现特定接口,从而暴露用于注入依赖对象的方法。容器在创建对象后,会调用接口方法并注入依赖对象

依赖注入的优点包括:

  1. 松耦合:依赖对象与被依赖对象之间的耦合度降低,对象的职责更加单一,易于理解和维护。

  2. 可测试性:依赖注入使得测试变得更加容易。可以通过注入模拟对象(Mock Objects)来进行单元测试和模块测试

  3. 可重用性:通过依赖注入,依赖对象可以被多个对象共享和重用,避免了重复创建和管理相同的依赖对象。

  4. 可扩展性:依赖注入使得应用程序的组件之间的关系更加灵活,可以轻松添加、替换和升级依赖对象

现代的开发框架和容器(如Spring框架、Spring BootGoogle Guice)提供了依赖注入的实现。它们通过注解、配置文件或其他方式,实现了依赖注入的自动化和便利性,使得开发者可以专注于业务逻辑的实现而不必过多关注依赖对象的创建和管理。

给出依赖的三种注入的方式的示例

当谈到依赖注入的三种主要方式时(构造函数注入、Setter方法注入和接口注入),我将为你提供每种方式的示例代码。

  1. 构造函数注入(Constructor Injection)的示例:
public class UserService {private UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository = userRepository;}// ...
}

在上面的示例中,UserService类通过构造函数接收一个UserRepository依赖对象,并将其赋值给成员变量userRepository。这种方式可以在创建UserService对象时,将UserRepository的实例传递给构造函数来进行注入。

  1. Setter方法注入(Setter Injection)的示例:
public class UserService {private UserRepository userRepository;public void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}// ...
}

在上述示例中,UserService类通过Setter方法 setUserRepository() 接收一个UserRepository依赖对象,并将其赋值给成员变量userRepository。这样,在创建UserService对象后,可以调用setUserRepository()方法来注入UserRepository的实例。

  1. 接口注入(Interface Injection)的示例:
public interface DiscountService {void setDiscountProvider(DiscountProvider discountProvider);
}public class DiscountServiceImpl implements DiscountService {private DiscountProvider discountProvider;@Overridepublic void setDiscountProvider(DiscountProvider discountProvider) {this.discountProvider = discountProvider;}// ...
}

在上述示例中,DiscountService是一个接口,定义了一个setDiscountProvider()方法,用于接收DiscountProvider依赖对象。DiscountServiceImpl类实现了该接口,并通过实现方法setDiscountProvider()来注入DiscountProvider的实例。

这些示例展示了依赖注入的不同方式,通过构造函数、Setter方法或接口方法来接收依赖对象,并将其赋值给类的成员变量或属性。在实际应用中,通常会结合使用这些方式,根据具体的需求和场景选择适合的注入方式。

从概念上讲讲自动注入

自动注入(Autowired)依赖注入(Dependency Injection,DI)的一种实现方式,最早由Spring框架引入并提出。

传统的依赖注入方式中,开发人员需要显式地在代码中声明依赖关系并手动进行依赖对象的注入。这种方式需要编写大量的重复代码,并且容易出错。

为了简化依赖注入的过程,Spring框架引入了自动注入的概念。自动注入允许开发人员使用特定的注解来标记依赖对象,而无需显式地进行依赖注入的代码编写。框架会自动查找和注入匹配的依赖对象,减少了手动注入的工作量,提高了开发效率。

自动注入的概念最早在Spring框架的早期版本中被提出。通过在目标类的字段、构造函数或Setter方法上添加@Autowired注解Spring容器会在创建对象时自动查找匹配的依赖对象,并将其注入到相应的位置。自动注入是根据类型进行匹配的,如果存在多个匹配的依赖对象,可以使用@Qualifier注解或通过名称来指定具体的依赖对象。

自动注入带来了以下好处:

  1. 简化开发:自动注入减少了手动注入的代码量,使代码更简洁和易于维护。

  2. 减少配置:开发人员无需手动配置每个依赖对象的注入,框架会自动完成依赖的查找和注入。

  3. 提高可测试性:通过自动注入,可以更容易地进行单元测试,可以轻松地替换依赖对象进行测试。

Spring框架的自动注入成为了它的核心特性之一,并且受到了广泛的应用和认可。后续的框架和技术也借鉴了Spring的自动注入概念,提供了类似的功能来简化依赖注入的过程。

Spring Boot中注解@Autowired,自动注入注解默认使用哪种注入方式

@Autowired注解可以使用以下几种依赖注入的方式:

  1. 按照类型进行注入(byType):这是@Autowired注解的默认方式,它会根据属性的类型在容器中查找对应的Bean,如果找到唯一的一个Bean,则进行注入。如果没有找到或者找到多个相同类型的Bean,则会抛出异常。这种方式可以用在字段、构造方法或者setter方法上。

  2. 按照名称进行注入(byName):这种方式需要配合@Qualifier注解来指定Bean的名称,它会根据属性的名称在容器中查找对应的Bean,如果找到则进行注入。如果没有找到,则会抛出异常。这种方式可以用在字段、构造方法或者setter方法上。

  3. 按照构造方法进行注入(constructor):这种方式是通过Bean对象的构造方法参数类型和容器中的Bean类型进行匹配,如果找到唯一的一个相同类型的Bean,则通过构造方法进行注入。如果没有找到或者找到多个相同类型的Bean,则会抛出异常。这种方式只能用在构造方法上

一般来说,按照类型进行注入最常用和方便的方式,但是如果你需要更精确地指定要注入的Bean,或者你想保证依赖对象不为空,那么你可以使用按照名称或者按照构造方法进行注入

给我一些上面自动注入的简单示例

好的,我将给你一些简单的示例。

按照类型进行注入的示例(大部分用的都是这种):

@Component
public class FooService {//在字段上使用@Autowired注解,按照类型进行注入@Autowiredprivate FooFormatter fooFormatter;
}@Component
public class FooFormatter {public String format() {return "foo";}
}

按照名称进行注入的示例:

@Component
public class BarService {//在字段上使用@Autowired和@Qualifier注解,按照名称进行注入@Autowired@Qualifier("barFormatter")private BarFormatter barFormatter;
}@Component("barFormatter")
public class BarFormatter {public String format() {return "bar";}
}

按照构造方法进行注入的示例:

@Component
public class BazService {private BazFormatter bazFormatter;//在构造方法上使用@Autowired注解,按照类型进行注入@Autowiredpublic BazService(BazFormatter bazFormatter) {this.bazFormatter = bazFormatter;}
}@Component
public class BazFormatter {public String format() {return "baz";}
}

依赖注入和自动注入的关联以及不同点

依赖注入(Dependency Injection,简称DI)和自动注入(Autowired)相关但不完全相同的概念。下面我将解释它们之间的关联和不同点:

关联

  1. 自动注入是依赖注入的一种实现方式。自动注入是指在容器启动或对象创建时,容器自动将所需的依赖对象注入到目标对象中,而无需手动显式地进行依赖注入

  2. Spring框架及其衍生的Spring Boot中,使用@Autowired注解实现自动注入。通过在目标对象的字段、构造函数或Setter方法上使用@Autowired注解,Spring容器会根据类型或名称自动查找并注入相应的依赖对象。

不同点:

  1. 控制权依赖注入是一种设计模式,强调将依赖对象的创建和管理责任转移到外部容器中。在依赖注入中,对象声明自己需要的依赖,但并不负责创建或获取依赖对象。相反,自动注入是依赖注入的一种具体实现方式,它是由容器在对象创建时自动完成依赖对象的注入。

  2. 显式性依赖注入通常需要在代码中显式地声明依赖关系,即通过构造函数、Setter方法或接口方法来接收依赖对象。这样可以清晰地表达对象之间的依赖关系。而自动注入不需要显式地声明依赖关系,容器会自动根据配置或默认规则完成注入

  3. 灵活性:依赖注入提供了更大的灵活性,允许对象在创建后替换依赖对象,或者在不同的环境中使用不同的依赖对象。通过手动注入,可以更容易地进行单元测试和模块替换。相比之下,自动注入的灵活性相对较低,依赖对象的选择通常由容器的配置或规则确定。

总结来说,依赖注入是一种设计模式,强调通过外部容器将依赖对象注入到目标对象中,以提高代码的可维护性和可测试性。

自动注入是依赖注入的一种具体实现方式,它通过使用@Autowired注解或其他类似的机制,在对象创建时自动完成依赖对象的注入。自动注入减少了手动注入的代码量,但相对来说可能牺牲了一些灵活性。

Spring Boot中,可以使用@Autowired注解实现自动注入,从而简化依赖注入的过程。


http://www.ppmy.cn/news/87607.html

相关文章

辅助生成: 低延迟文本生成的新方向

大型语言模型如今风靡一时,许多公司投入大量资源来扩展它们规模并解锁新功能。然而,作为注意力持续时间不断缩短的人类,我们并不喜欢大模型缓慢的响应时间。由于延迟对于良好的用户体验至关重要,人们通常使用较小的模型来完成任务…

webpack简单的搭建和使用

随便创建一个空的文件夹,例如说:explore 然后我们测试一下我们的node是否存在 可以正确打印出版本 我们再次输入:npm init -y 创建一个package.json文件 出现这样的情况就成功了 然后我们要安装webpack在终端上输入命令: npm i …

RK3568平台开发系列讲解(驱动基础篇)RK平台UART的使用

🚀返回专栏总目录 文章目录 一、引脚定义1.1 UART91.2 RS232和RS485二、设备树配置三、调试3.1 连接硬件3.2 打开主机的串口终端3.3 板子发送数据3.4 板子接收数据3.5 主机退出kermit串口连接四、UART2普通串口配置沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇…

Python欧几里得距离变换

文章目录 欧氏距离变换distance_transform_edt其他距离变换函数 欧氏距离变换 edt,即Euclidean distance transform.,欧氏距离变换。对于一个二值矩阵 A A A,元素 a ∈ A a\in A a∈A,则 edt ⁡ ( a ) \operatorname{edt}(a) edt…

虚拟机磁盘扩容及重新分区方法

创建虚拟机的时候,如果分配的磁盘过小,在后续的使用时可能需要进行扩容,在扩容后你会发现好像磁盘并没有变大,这时候就需要进行重新分区 一、虚拟机扩容 在将需要扩容的虚拟机关机后,点击VMware的菜单栏中的虚拟机&…

【2023 · CANN训练营第一季】MindSpore模型快速调优攻略 第二章——MindSpore调试调优

1.生态迁移 生态迁移工具使用示例 生态迁移工具技术方案 不同框架间模型定义前端表达差别巨大(相同算子的API技术难点 、 算子功能、模型构建方式差别较大); 对于同一框架,不管前端表达差异如何,最终对应的计算 图是相似的。因此提出&#x…

每天一个面试题之==和equals的区别是什么?

==和equals的区别是什么? ""是一个关系运算符,关系运算符可以用来进行数据和数据之间的比较,而在java中数据类型大致可以分为两大类分别是基本数据类型和引用数据类型。 基本数据类型包含 byte&#xff0c…

【C++】布隆过滤器

文章目录 布隆过滤器的引入布隆过滤器的概念如何选择哈希函数个数和布隆过滤器长度布隆过滤器的实现布隆过滤器的优缺点 布隆过滤器的引入 我们在使用新闻客户端看新闻时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉那些已经看过…