当前位置:首页 » 《关于电脑》 » 正文

【Spring】Ioc&DI

29 人参与  2024年11月17日 16:41  分类 : 《关于电脑》  评论

点击全文阅读


 ?个人主页: 中草药

?专栏:【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、优点

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

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 方法,用于接收被依赖类的实例。例如 

@Controllerpublic 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 框架中): 

@Controllerpublic 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对象时,会报错:

@Componentpublic 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;     }}@Controllerpublic 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://m.zhangshiyu.com/post/187766.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1