0


【Spring】Ioc&DI

🔥个人主页: 中草药

🔥专栏:【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的⼀套快速开发整合包


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

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

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

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

标签: spring java 后端

本文转载自: https://blog.csdn.net/2302_79806056/article/details/143271383
版权归原作者 中草药z 所有, 如有侵权,请联系我们删除。

“【Spring】Ioc&DI”的评论:

还没有评论