• 深入浅出讲解Spring IOC和DI的区别


    Spring IOC和DI的区别

    一,介绍

    前言

            很多人都会把ioc和di说成同一个东西,其实IOC和DI虽然在概念上可以笼统地视为同一事物,但其本质上存在区别。IOC(Inverse of Control,控制反转)从容器的角度描述,而DI(Dependency Injection,依赖注入)则从应用程序的角度描述。换言之,IOC是依赖倒置原则的设计思想,而DI则是该原则的具体实现方式。因此,我们希望能够更加严谨地区分这两个概念,以更好地理解和应用它们。

    1.什么是IOC

            Spring IOC(控制反转)是一种设计模式,是Spring框架的核心,它通过将对象之间的依赖关系交由容器来管理和注入,实现了组件之间解耦、松耦合的目的。在传统的Java开发中,对象之间的依赖关系通常是通过手动创建和维护对象之间的引用关系来实现的,这样会带来很多问题,例如代码的可读性、可维护性、可测试性等方面都会受到影响。使用IOC后,无需手动创建和维护对象之间的引用关系,因为Spring容器将自动完成这些工作,并且可以根据需要动态地注入不同类型的对象或数据,从而实现灵活性更强、代码质量更高的应用程序开发。

    简单理解就是原本我们创建对象的过程是我们手动来管理的,比如User user = new User(); 而使用ioc就是来解决这个问题的,交给容器来管理创建以及管理的过程

    IOC容器的初始化有两种方式:饿汉式初始化和懒加载。

    饿汉式初始化是指在容器启动时,立即进行对象的创建和初始化。这种方式适合单例对象,可以保证对象在系统启动时便可用,避免因为对象未初始化而导致的空指针异常等问题。

    懒加载则是指只有在需要使用对象时,才进行对象的创建和初始化。这种方式适合非单例对象,可以降低系统启动时间和内存消耗。Spring IoC容器默认使用懒加载方式,只有在使用`@Lazy`注解或者在配置文件中进行特别声明后,才会使用饿汉式初始化方式。

    下面是两种初始化方式的示例:

    1. 饿汉式初始化方式
     

    1. @Component
    2. public class MySingletonBean {
    3.     // ...
    4. }
    5. @Configuration
    6. public class AppConfig {
    7.     @Bean
    8.     public MySingletonBean mySingletonBean() {
    9.         return new MySingletonBean();
    10.     }
    11. }

    在这个示例中,`MySingletonBean`是一个单例对象,通过在配置类中定义`@Bean`方法来进行饿汉式初始化。

    2. 懒加载方式

    1. @Component
    2. @Lazy
    3. public class MyLazyBean {
    4.     // ...
    5. }

    在这个示例中,`MyLazyBean`是一个非单例对象,在它上面使用了`@Lazy`注解,表示使用懒加载方式进行初始化。当应用程序需要使用`MyLazyBean`时,才会触发对象的创建和初始化。

    2.什么是DI

            Spring DI(依赖注入)是Spring框架中的一个核心特性,它是实现控制反转(IOC)的具体方式之一。DI指的是通过外部配置或注解的方式,将一个对象所依赖的其他对象(依赖)自动注入到该对象中,而不需要在代码中显式地创建和管理这些依赖对象。

    通过使用DI,我们可以将对象之间的依赖关系从代码中解耦出来,提高代码的可读性、可维护性和可测试性。Spring框架通过提供不同的DI实现方式(如构造方法注入、Setter方法注入、注解注入等),使得开发者可以根据需求选择合适的注入方式。

    例如,我们可以使用构造方法注入,在对象创建时通过构造方法接收所需的依赖对象;或者使用Setter方法注入,在对象创建后通过Setter方法设置所需的依赖对象;还可以使用注解注入,在代码中使用注解标记需要注入的依赖对象。这样,我们就能够以一种更灵活、简洁的方式管理对象之间的依赖关系,提升开发效率和代码质量。

    3.为什么要使用控制反转,能给我带来哪些好处

            知其然而不知其所以然,是指只知道事物的表面现象!只知道用只是之所以然要明白为什么要用才是知其然而知其所以然。用一东西的时候而不是会用就可以了,要明白为什么要用,难道就没有别的替代方法吗,答案肯定是有的,有人会说就是好用才用的,说的没有错,但是这样我认为并没有去思考为什么要用它为不用别的。接下来我来重点讲解

    使用Spring的控制反转(IOC)能够带来以下好处:

    1. 解耦合:将程序中的依赖关系转到Spring容器进行配置,可以减少程序模块之间的耦合。这样,当一个组件发生改变时,不会影响到系统中其他组件的正常运行。

    2. 管理对象的生命周期:Spring容器负责管理对象的生命周期,当对象不再被使用时,容器会自动销毁其实例,这可以避免内存泄漏等问题。

    3. 提高代码重用性:通过将业务逻辑从代码中分离出来,可以使得代码更加可重用,降低代码的维护成本。

    4. 模块化开发:Spring容器可以组织程序中的所有对象,使得代码具有良好的层次结构和模块化特性,提高代码的可读性和可维护性。

    5. 容易测试:通过控制反转,我们可以使用Mock对象来替代真正的对象进行单元测试,从而使得测试变得更加容易,可以提高代码的质量。

    总之,使用Spring控制反转可以使得代码的耦合度更低、可重用性更高、可维护性更好,使得开发工作变得更加高效。

    二,代码具体实现

    在Spring Boot中,IoC的实现方式与传统的Spring框架类似,但会更加简化和自动化。下面是一个使用Spring Boot实现IoC的示例:

    1. 创建一个Spring Boot项目,并添加所需的依赖。2. 编写一个接口和相应的实现类:

     

    1. // 定义一个接口
    2. public interface MessageService {
    3.     String getMessage();
    4. }
    5. // 实现接口
    6. @Service
    7. public class HelloWorldService implements MessageService {
    8.     @Override
    9.     public String getMessage() {
    10.         return "Hello, World!";
    11.     }
    12. }

    3. 在启动类上使用`@SpringBootApplication`注解,它包含了`@ComponentScan`注解,来自动扫描并创建所有需要的Bean。

    1. @SpringBootApplication
    2. public class Application {
    3.     public static void main(String[] args) {
    4.         SpringApplication.run(Application.class, args);
    5.     }
    6. }


     

    4. 在其他需要使用该服务的地方,可以通过`@Autowired`注解来自动注入该Bean。

    1. @RestController
    2. public class MyController {
    3.     @Autowired
    4.     private MessageService messageService;
    5.     @GetMapping("/message")
    6.     public String getMessage() {
    7.         return messageService.getMessage();
    8.     }
    9. }

    在这个示例中,我们创建了一个名为 `HelloWorldService` 的bean,并使用 `@Service` 注解来标识它是一个服务类。然后,在启动类中使用 `@SpringBootApplication` 注解来开启Spring Boot应用,并自动扫描和创建所有需要的Bean。

    在 `MyController` 中,我们使用 `@Autowired` 注解自动注入了 `MessageService` 类型的bean。然后,在 `/message` 接口中调用 `getMessage()` 方法并返回结果。

    Spring Boot会自动注入相关的Bean,并管理它们的生命周期,无需手动配置XML文件。同时,Spring Boot也提供了默认的配置,让开发者可以快速开始项目,减少了繁琐的配置过程。

    1.详细详解 IOC

    在经典的三层架构中,IoC(控制反转)的具体表示通常是在数据访问层(Repository或DAO)和业务逻辑层(Service)之间的交互。具体来说,IoC容器负责管理并注入数据访问层所需的依赖对象,例如数据库连接、事务管理等。

    在这种情况下,数据访问层(Repository或DAO)负责与数据库进行交互,而业务逻辑层(Service)则负责处理业务规则和流程。业务逻辑层需要依赖数据访问层提供的持久化功能,但它并不直接依赖具体的实现类,而是通过IoC容器来获取相应的依赖对象。

    通过IoC容器的管理,我们可以在业务逻辑层中使用依赖注入(Dependency Injection)来获取和使用数据访问层的对象,从而实现了对象之间的解耦和灵活性。这样,在需要替换或扩展特定功能时,只需调整IoC容器的配置即可,而不需要修改业务逻辑层的代码。

    总结起来,IoC的具体表示通常体现在数据访问层和业务逻辑层之间的交互,通过IoC容器的管理和依赖注入来实现对象的解耦和可替换性。这样可以提高代码的可维护性和可测试性,并支持应用程序的灵活性和扩展性。

    2.详细详解 DI

    DI(依赖注入)是IoC(控制反转)的一种实现方式,它通过将对象的依赖关系交由容器来管理,从而解耦对象之间的依赖关系。而@Autowired注解是Spring框架中实现依赖注入的一种方式。使用@Autowired注解可以将需要依赖的对象自动注入到目标对象中,由Spring容器负责创建和管理这些被注入的Bean对象。

    对于@Autowired注解,它确实是由它来实现依赖注入,将依赖对象注入到IOC容器中,并由容器来负责管理Bean对象的生命周期。当我们在需要使用某个依赖对象的地方添加@Autowired注解后,Spring会自动扫描并查找与该依赖类型匹配的Bean对象,并自动将其注入进来。

    所以您可以说@Autowired注解可以实现依赖注入,由它将依赖对象注入到IoC容器进行管理,并由容器负责管理Bean对象的生命周期。非常感谢您的理解和提问!

    简单来说 而di就好理解了@Autowired注解 由它依赖注入到ioc容器中由容器来管理bean的生命周期

    三,DI依赖注入的几种实现方式
     

    @Resource 这里代码我就不过多介绍了

    我来给您提供几种常见的Spring DI(依赖注入)实现方式,并附上相应的代码示例。

    1. 构造函数注入(Constructor Injection):

    1. public class UserService {
    2.     private UserRepository userRepository;
    3.     @Autowired
    4.     public UserService(UserRepository userRepository) {
    5.         this.userRepository = userRepository;
    6.     }
    7.     // 其他方法...
    8. }


    2. 属性注入(Setter Injection):

    1. public class UserService {
    2.     private UserRepository userRepository;
    3.     @Autowired
    4.     public void setUserRepository(UserRepository userRepository) {
    5.         this.userRepository = userRepository;
    6.     }
    7.     // 其他方法...
    8. }


    3. 接口注入(Interface Injection):

    1. public interface UserRepositoryAware {
    2.     void setUserRepository(UserRepository userRepository);
    3. }
    4. public class UserService implements UserRepositoryAware {
    5.     private UserRepository userRepository;
    6.     @Override
    7.     public void setUserRepository(UserRepository userRepository) {
    8.         this.userRepository = userRepository;
    9.     }
    10.     // 其他方法...
    11. }


    4. 注解注入(Annotation Injection):

    1. public class UserService {
    2.     @Autowired
    3.     private UserRepository userRepository;
    4.     // 其他方法...
    5. }


    5. XML配置注入(XML Configuration Injection):
    在XML配置文件中定义Bean和依赖项,并通过元素进行注入。示例:

    1. <bean id="userRepository" class="com.example.UserRepositoryImpl" />
    2. <bean id="userService" class="com.example.UserService">
    3.     <property name="userRepository" ref="userRepository" />
    4. </bean>

    上述示例展示了几种常见的Spring DI实现方式。根据您的需求和项目结构,选择适合的方式来实现依赖注入。 

    四,@Autowired,@Resource

    1.介绍

    `@Autowired`和`@Resource`都是Java的注解,用于实现依赖注入(DI)功能。它们可以将依赖对象自动注入到需要的地方,简化了手动创建和管理对象之间的依赖关系的过程。

    1. `@Autowired`注解:
       - `@Autowired`是Spring框架提供的注解,用于自动装配依赖对象。
       - 使用`@Autowired`可以直接在字段、构造方法、Setter方法或者任意方法上标注,Spring将根据类型进行自动装配。如果有多个合适的候选对象,可以使用`@Qualifier`注解指定具体的bean名称。
       - 示例:

    1. @Resource
    2. private UserService userService;


         Spring将会自动寻找名为`userService`的`UserService`类型的bean,并将其注入到该字段中。

    2. `@Resource`注解:
       - `@Resource`是JavaEE标准中定义的注解,也可以实现依赖注入的功能。
       - `@Resource`既可以根据名称进行自动装配,也可以根据类型进行自动装配,具备更强的灵活性,默认按照名称进行装配。
       - 示例:
         

    1. @Resource
    2.      private UserService userService;


         @Resource`将会根据字段名称`userService`来查找并注入对应的bean。

    两者的使用场景和功能类似,但在具体实现细节和使用上有一些差异。一般来说,如果项目使用的是Spring框架,推荐使用`@Autowired`注解;如果是JavaEE标准的项目,可以使用`@Resource`注解。当然,在实际使用中也可以根据具体需求选择合适的注解。

    2.区别

    `@Autowired`和`@Resource`注解的区别如下:

    1. 来源:`@Autowired`是Spring框架提供的注解,而`@Resource`是JavaEE标准中定义的注解。

    2. 自动装配方式:`@Autowired`按照类型进行自动装配,默认情况下要求依赖对象必须存在。如果存在多个匹配的bean,可以使用`@Qualifier`注解指定具体的bean名称。而`@Resource`默认按照名称进行自动装配,可以根据`name`属性指定特定的bean名称,也可以根据`type`属性进行按类型查找。

    3. 包含范围:`@Autowired`只能用于字段、构造方法、Setter方法或者任意方法上。而`@Resource`既可以标注在字段上,也可以标注在setter方法上。

    4. 引入的包:`@Autowired`需要导入`org.springframework.beans.factory.annotation.Autowired`包,而`@Resource`需要导入`javax.annotation.Resource`包。

    5. 注解来源:`@Autowired`是Spring框架自带的注解,不依赖于JavaEE环境。而`@Resource`是JavaEE标准中定义的注解,它依赖于JavaEE环境。

    综上所述,`@Autowired`和`@Resource`注解在实现依赖注入功能上有些许差异。`@Autowired`更加强调按照类型进行自动装配,而`@Resource`更加灵活,既可以按照名称进行自动装配,也可以按照类型进行自动装配。在使用上,如果是Spring框架的项目,一般推荐使用`@Autowired`注解;如果是JavaEE标准的项目,可以使用`@Resource`注解。但实际选择可以根据具体需求和个人偏好来确定。

    五,总结

    本文从IOC和DI的概念、区别以及具体实现方式入手,介绍了Spring框架中实现依赖注入的基本原理、好处和常见实现方式,最后对比了@Autowired和@Resource注解的区别和使用场景。总体来说,IOC和DI是Spring框架的核心特性,通过容器管理和注入对象之间的依赖关系,极大地提高了代码的灵活性、可维护性和可重用性。同时,根据具体需求和项目结构,选择合适的注解和实现方式可以更好地实现依赖注入的功能,提升开发效率和代码质量。

  • 相关阅读:
    【漏洞通告】CVE-2022-39198 Apache Dubbo Hession反序列化漏洞
    Leetcode 85.最大矩形(困难)
    切记:Python迭代器只可以读取一次,忽略会有意想不到的麻烦。
    遍历树形结构记录
    CloudCompare&PCL 道格拉斯普克算法(DP)
    ssm+vue的OA办公系统(有报告)。Javaee项目,ssm vue前后端分离项目。
    折半查找的判定树
    【OpenCV DNN】Flask 视频监控目标检测教程 01
    【Vue】描述项目中两个功能模块的业务(一点见解)
    海思3559万能平台搭建:YUV422的踩坑记录
  • 原文地址:https://blog.csdn.net/qq_49841284/article/details/133966215