当前位置: 首页 > article >正文

【Spring】IocDI

 🔥个人主页: 中草药

🔥专栏:【Java】登神长阶 史诗般的Java成神之路


        在 Java 开发的世界里,Spring 框架无疑是一颗璀璨的巨星,而其中的控制反转(Inversion of Control,简称 Ioc)依赖注入(Dependency Injection,简称 DI)更是其核心特性之一。今天,就让我们一起深入探索 Spring 中的 Ioc 和 DI。

🥼一、IoC (Inversion of Control)

1、概念

        Ioc,即控制反转(Inversion of Control),是一种重要的设计思想。

       在传统的编程模式中,对象的创建和依赖关系的管理通常由程序员在代码中显式地进行。例如,一个对象 A 如果依赖于对象 B,那么在对象 A 的代码中就需要主动去创建对象 B。而在 Spring 的 Ioc 容器中,对象的创建和依赖关系的管理被反转了过来,不再由对象自身来管理,而是由容器来负责。

举例:

2、理解

需求:造一辆车

我们的实现思路:

        先设计轮子(Tire),然后根据轮子的大小设计出底盘(Bottom),接着根据底盘设计出车身(Framework),最后根据车身设计好整个的汽车(Car),这里存在一个依赖关系

代码如下:

public class Car {
    private Framework framework;
    public Car(int size) {
        this.framework = new Framework(size);
        System.out.println("car init...");
    }

    public void run() {
        System.out.println("car run...");
    }
}

public class Framework {
    private Bottom bottom;

    public Framework(int size) {
        this.bottom = new Bottom(size);
        System.out.println("framework init...");
    }
}

public class Bottom {
    private Tire tire;
    public Bottom(int size) {
        this.tire = new Tire(size);
        System.out.println("bottom init...");
    }
}

public class Tire {
    private int size;

    public Tire(int size) {
        System.out.println("tire size:" + size);
    }
}

当我们用IoC的思想去修改以上代码

如图,改进之后的控制权发生了翻转,不再是使用方创建并控制对象,而是把依赖对象注入到当前的对象,依赖对象的控制权不再由当前类控制 

   public class Car {
       private Framework framework;
   
       public Car(Framework framework) {
           this.framework = framework;
           System.out.println("Car init....");
       }
   
       public void run() {
           System.out.println("Car run...");
       }
   }
   
   class Framework {
       private Bottom bottom;
   
       public Framework(Bottom bottom) {
           this.bottom = bottom;
           System.out.println("Framework init...");
       }
   }
   
   class Bottom {
       private Tire tire;
   
       public Bottom(Tire tire) {
           this.tire = tire;
           System.out.println("Bottom init...");
       }
   }
   
   class Tire {
       private int size;
   
       public Tire(int size) {
           this.size = size;
           System.out.println("轮胎尺寸:" + size);
       }
   }

3、优点

  1. 资源集中管理:LoC实现了资源的集中管理,实现资源的可配置和易管理
  2. 松耦合:降低使用资源双方的依赖程度

Spring就是一种IoC容器,帮助我们来进行资源管理

🦺二、DI(Dependency Injection)

1、概念

        在软件开发中,当一个类(称为依赖类)需要使用另一个类(称为被依赖类)的功能时,传统的做法是在依赖类中直接创建被依赖类的实例。但这样会导致依赖类和被依赖类之间的耦合度较高,不利于代码的维护和扩展。

        而依赖注入则是将被依赖类的实例通过外部方式(如构造函数、Setter 方法、字段注入等)注入到依赖类中,从而实现依赖类和被依赖类之间的解耦。

IoC是一种思想,DI相当于他的具体实现

 2、实现方式

        1.属性注入,主要通过@Autowired实现的,例如: 

@Controller
    public class UserController {
     //注⼊⽅法1: 属性注⼊
     @Autowired
     private UserService userService;

     public void sayHi(){
         System.out.println("hi,UserController...");
         userService.sayHi();
     }
}

        2.构造方法注入:在依赖类中提供 Setter 方法,用于接收被依赖类的实例。例如 

@Controller
public class UserController2 {
     //注⼊⽅法2: 构造⽅法
     private UserService userService;

     @Autowired
     public UserController2(UserService userService) {
     this.userService = userService;
     }

     public void sayHi(){
         System.out.println("hi,UserController2...");
         userService.sayHi();
     }
}

        3.Setter方法注入:使用注解等方式直接在依赖类的字段上注入被依赖类的实例。例如(在 Spring 框架中): 

@Controller
public class UserController3 {
     //注⼊⽅法3: Setter⽅法注⼊
     private UserService userService;

     @Autowired
     public void setUserService(UserService userService) {
         this.userService = userService;
     }

     public void sayHi(){
         System.out.println("hi,UserController3...");
         userService.sayHi();
     }
}

3、优缺点对比

~属性注入

        优点:只能针对IoC容器,并且只有在使用时抛出NPE

        缺点:不能注入一个Final修饰的属性

~构造函数注入(Spring 4.x推荐)

        优点:

               1. 可以注入Final修饰的属性

                2.注入的对象不会被修改

                3.依赖对象在使用之前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而

                构造方法是在类加载阶段会执行的

                4.通用性好,构造方法是JDK支持的,所以他适用于任何框架

        缺点:注入多个对象,代码会比较繁琐

~Setter注入 (Spring 3.x推荐)

        优点:方便在类实例之后,重新对该对象进行配置或者注入

        缺点:不能注入Final修饰的属性,注入对象可能会被改变

4、@Autowired存在问题

如下代码,当同一类型出现多个Bean对象时,会报错:

@Component
public class BeanConfig {
     @Bean("u1")
     public User user1(){
         User user = new User();
         user.setName("zhangsan");
         user.setAge(18);
         return user;
     }

     @Bean
     public User user2() {
         User user = new User();
         user.setName("lisi");
         user.setAge(19);
         return user;
     }
}

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    //注入user
    @Autowired

    private User user;
    public void sayHi(){
         System.out.println("hi,UserController...");
         userService.sayHi();
         System.out.println(user);
    }
}

运行结果:

报错原因:非唯一的Bean对象

Spring提供了以下三种解决方案

1.@Primary

  • 作用:当存在多个相同类型的 bean 可供注入时,使用@Primary注解可以指定一个首选的 bean。如果没有其他更具体的限定条件,Spring 将优先选择被标记为@Primary的 bean 进行注入。
  • 示例:
   // 定义两个相同类型的 bean
   @Component
   public class ServiceA implements MyService {
       //...
   }

   @Component
   @Primary
   public class ServiceB implements MyService {
       //...
   }

   @Component
   public class Consumer {
       @Autowired
       private MyService service;
       //...
   }

在上面的例子中,当Consumer类需要注入MyService类型的 bean 时,如果没有其他更具体的限定条件,Spring 会优先选择ServiceB进行注入,因为它被标记为@Primary

2.@Qualifier

  • 作用:当存在多个相同类型的 bean 时,可以使用@Qualifier注解结合一个特定的名称来明确指定要注入的 bean。
  • 示例:
   @Component
   public class ServiceA implements MyService {
       //...
   }

   @Component
   public class ServiceB implements MyService {
       //...
   }

   @Component
   public class Consumer {
       @Autowired
       @Qualifier("serviceA")
       private MyService service;
       //...
   }

在这个例子中,通过@Qualifier("serviceA")明确指定了要注入名为serviceA的 bean,也就是ServiceA类的实例。

3.@Resource

  • 作用:@Resource注解是 Java EE 规范中的注解,Spring 也支持该注解进行依赖注入。它可以通过名称或类型进行注入。如果只指定了名称,Spring 会根据名称查找 bean;如果没有指定名称,会根据类型进行注入。
  • 示例:
   @Component
   public class ServiceA implements MyService {
       //...
   }

   @Component
   public class ServiceB implements MyService {
       //...
   }

   @Component
   public class Consumer {
       @Resource(name = "serviceA")
       private MyService service;
       //...
   }

这里通过@Resource(name = "serviceA")指定注入名为serviceA的 bean,即ServiceA类的实例。=

        这些注解为解决多个相同类型的 bean 注入问题提供了灵活的方式,可以根据具体的需求选择合适的注解来确保正确的依赖注入。

5、@Autowired和@Resource的区别

  • @Autowired是spring框架提供的,@Resource是JDK提供的注解
  • @Autowired默认是按类型注入的,而@Resource优先是按照名称注入的,@Resource提供更多的参数设置

 @Autowired的装配顺序

👔三、Spring, Spring Boot 和Spring MVC的关系以及区别

1、Spring

        简单而言是一个开发应用的框架---轻量级,一站式,模块化,母的是用于简化企业级应用程序的开发。
        主要功能:管理对象,以及对象之间的依赖关系,面向切面编程,数据库事务管理,数据访问,web框架支持
        具有高度可开放性,可以无缝继承第三方框架,不如数据访问框架(Hibernate,JPA),web框架(Status,JSF)

2、Spring Boot

        Spring Boot是对Spring的⼀个封装, 为了简化Spring应用的开发而出现的,中小型企业,没有成本研究自己的框架, 使用Spring Boot 可以更加快速的搭建框架, 降级开发成本, 让开发人员更加专注于Spring应用的开发,而无需过多关注XML的配置和⼀些底层的实现

        Spring Boot 是个脚手架, 插拔式搭建项目, 可以快速的集成其他框架进来.

        比如想使用SpringBoot开发Web项目, 只需要引入Spring MVC框架即可, Web开发的工作是SpringMVC完成的, 而不是SpringBoot, 想完成数据访问, 只需要引入Mybatis框架即可.

        Spring Boot只是辅助简化项目开发的, 让开发变得更加简单, 甚至不需要额外的web服务器, 直接生成jar包执行即可.

3、Spring MVC  

        Spring MVC是Spring的一个子框架, Spring诞生之后, 大家觉得很好用, 于是按照MVC模式设计了一个 MVC框架(一些用Spring 解耦的组件), 主要用于开发WEB应用和网络接口,所以, Spring MVC 是⼀个Web框架

        Spring MVC基于Spring进行开发的, 天生的与Spring框架集成. 可以让我们更简洁的进行Web层开发, 支持灵活的 URL 到页面控制器的映射, 提供了强大的约定大于配置的契约式编程支持, 非常容易与其他视图框架集成,如 Velocity、FreeMarker等

Spring MVC和Spring Boot都属于Spring,Spring MVC 是基于Spring的一个的MVC 框架,而Spring Boot 是基于Spring的⼀套快速开发整合包


欲望以提升热忱,毅力以磨平高山。

🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀

以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐

  制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸


http://www.kler.cn/a/371444.html

相关文章:

  • 【分布式知识】分布式对象存储组件-Minio
  • Camp4-L0:Linux 前置基础
  • 【Spring框架】Spring框架的开发方式
  • Flutter加载本地HTML的优雅解决方案:轻松实现富文本展示
  • Spring Boot技术中小企业设备管理系统设计与实践
  • django中的类属性和类方法
  • 端到端自动驾驶模型SparseDrive论文阅读笔记
  • HarmonyOS:@Watch装饰器:状态变量更改通知
  • webAssembly初探
  • Python BeautifulSoup 实战案例:抓取网页并提取数据
  • 【C++】智能指针:解决内存泄漏、悬空指针等问题
  • 【Unity基础】初识UI Toolkit - 编辑器UI
  • 简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef
  • PyTorch模块介绍
  • 【IC每日一题】
  • 【架构-36】常见的各类锁的特点
  • C++学习:类和对象(二)
  • [ 问题解决篇 ] 解决远程桌面安全登录框的问题
  • 3个模型的交互式多模型IMM,基于EKF的目标跟踪实例(附MATLAB代码)
  • java web调试时清理当前网址的缓存
  • 3.1.3 虚存页面的映射
  • Java学习笔记(九)
  • 云原生后端:现代应用架构的核心力量
  • JavaWeb——Web入门(2/9)-SpringBootWeb:快速入门(入门程序需求、开发步骤、项目相关文件说明、小结)
  • 【Linux网络编程】 --- Linux权限理解
  • ICM20948 DMP代码详解(106)