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

Spring(5)——IoC DI

初步理解IoC & DI

什么是Spring?

用一句话概括就是:Spring是包含了众多工具方法的IoC容器

那么问题又来了,什么是容器?什么是IoC容器?

1.0 什么是容器

容器是⽤来容纳某种物品的(基本)装置。⸺来自:百度百科

在开发中: List/Map是数据存储容器,Tomcat是Web容器。

1.1 什么是IoC

在早期的开发中和对于初学者的学习过程中,整个项目中对象的数量不多,对象的属性不多,对象之间的依赖不强。

在这里插入图片描述

但是随着技术的发展,一个项目中对象数量越来越多,属性越来越多,对象之间的依赖也越来越复杂。甚至于多个对象构成一个组件,组件之间的依赖也很复杂。

在这里插入图片描述

此时我们就需要一个平台,平台负责对象的生成和装配。

在这里插入图片描述

作为开发者我们只需要将对象的生产方法告诉平台,即更多的关注功能的实现。

而这个平台就是Spring的IoC容器,平台所提供的装配好依赖关系的对象,在Spring中叫做Bean

再通过一个场景去理解:在一个项目中两个服务都需要连接数据库,我们需要分别创建连接数据库的对象,同时还需要创建一些依赖对象,但是有了IoC容器后,容器会创建好一个连接对象,当我们的服务中需要数据库连接对象的时候,只需要进行相应注解的标注,容器就会自动将这个依赖对象注入。

IoC是Spring的核⼼思想,本质是 “将程序的控制权交给框架”,开发者不再需要手动管理对象和依赖,而是由容器统一调度。

IoC:Inversion of Control(控制反转),也就是说Spring是⼀个"控制反转"的容器。

这个反转主要体现在以下几个方面:

  1. 对象创建权的反转
  • 传统方式:开发者需要手动通过 new 关键字创建对象,并显式管理对象之间的依赖关系(例如通过构造函数或 setter 方法传递依赖)。

    // 传统方式:开发者手动创建对象和依赖
    UserService userService = new UserService();
    UserDao userDao = new UserDao();
    userService.setUserDao(userDao);
    
  • IoC 方式:对象的创建、依赖注入、生命周期管理均由容器(如 Spring)负责。开发者只需通过配置(XML/注解)或代码定义对象的依赖关系,容器会自动完成对象的实例化和依赖装配。

    // Spring IoC:容器自动注入依赖
    @Service
    public class UserService {
        @Autowired  // 容器自动注入 UserDao
        private UserDao userDao;
    }
    

    其实IoC我们在前⾯已经使⽤了,我们在前⾯讲到,在类上⾯添加 @RestController @Controller 注解,就是把这个对象的创建方法交给Spring管理,Spring框架启动时就会加载该类,在容器中创建该类的对象。把对象交给Spring管理,就是IoC思想。

  1. 依赖管理权的反转
  • 传统方式:对象需要主动获取依赖(例如从工厂类或全局单例中获取),导致代码与具体实现强耦合。

    // 传统方式:对象主动获取依赖(紧耦合)
    public class UserService {
        private UserDao userDao = DaoFactory.getUserDao();
    }
    
  • IoC 方式:依赖由容器主动“注入”到对象中,对象是被动接受依赖。这种方式解耦了对象和依赖的具体实现,依赖关系由外部(容器)定义。

    // Spring IoC:依赖由容器注入(松耦合)
    public class UserService {
        private UserDao userDao;  // 依赖由容器注入
    }
    
  1. 控制流的反转
  • 传统程序:代码逻辑由开发者编写的代码直接控制,主流程由开发者显式调用。

    public static void main(String[] args) {
        UserService userService = new UserService();
        userService.doSomething();
    }
    
  • IoC 程序:程序的主流程由框架(如 Spring)控制,开发者只需通过配置或注解定义组件,框架负责调度和执行。

    @SpringBootApplication
    public class MyApp {
        public static void main(String[] args) {
            SpringApplication.run(MyApp.class, args); // 控制权交给 Spring
        }
    }
    

可以理解为传统程序中,开发者要显式的点击开始,然后程序就开始按照提前写好的顺序去执行了,在IoC程序中,点击开始,程序不会按照某个顺序去执行,流程由框架驱动,开发者只需定义组件和处理逻辑,框架决定何时调用它们。

关键总结

  • 反转的核心:将对象的创建、依赖管理、程序流程的控制权从开发者手中转移到容器或框架。
  • 解决的问题:解耦组件之间的依赖关系,使代码更灵活、可维护性更高(例如通过依赖注入实现面向接口编程)。
  • 实际体现:开发者不再需要编写 new、不再需要手动管理依赖关系、不再需要控制程序的主流程。

通过 IoC,开发者可以更专注于业务逻辑的实现,而非底层对象的创建和管理。

1.2 什么是DI

在 Spring 框架中,依赖注入(Dependency Injection) 是实现控制反转(IoC)的核心技术,它通过容器自动管理对象之间的依赖关系。

下面通过一个小案例来理解依赖注入。

这是原本的代码:

//用来提供数据
public class BookDao {
    
public List<BookInfo> mockData() {
	List<BookInfo> books = new ArrayList<>();

    for (int i = 0; i < 5; i++) {
		BookInfo book = new BookInfo();
		book.setId(i);
		book.setBookName("书籍" + i);
		book.setAuthor("作者" + i);
		book.setCount(i * 5 + 3);
		book.setPrice(new BigDecimal(new Random().nextInt(100)));
		book.setPublish("出版社" + i);
		book.setStatus(1);
		books.add(book);
		}
return books;
	}
    
}
//使用数据
public class BookService {
  
	private BookDao bookDao = new BookDao();
	public List<BookInfo> getBookList() {
	List<BookInfo> books = bookDao.mockData();
	for (BookInfo book : books) {
		if (book.getStatus() == 1) {
		book.setStatusCN("可借阅");
		} else {
		book.setStatusCN("不可借阅");
		}
	}
	return books;
	}
}

可以看到在BookService中我们主动new了一个BookDao对象。这里需要介绍两个注解

@Component & @Autowired

1. @Component:标记类为 Spring Bean

  • 作用:告诉 Spring 容器,“这个类需要被管理,请把它创建成一个 Bean”。
  • 使用场景:标记任意需要被 Spring 管理的类(如工具类、服务类、数据访问类)。

2. @Autowired:自动注入依赖

  • 作用:告诉 Spring 容器,“请把匹配的 Bean 自动注入到这个字段/构造器/方法中”。
  • 使用场景:在需要依赖其他 Bean 的地方(如 Service 依赖 DAO)。

将这两个注解运用到上面的案例中:

//告诉 Spring 容器,“这个类需要被管理,请把它创建成一个 Bean”。
@Component
public class BookService {
    //告诉 Spring 容器,“请把匹配的 Bean 自动注入到这个字段/构造器/方法中”。
    @Autowired
    private BookDao bookDao;
    public List<BookInfo> getList(){
        List<BookInfo> books = bookDao.mockData();
        //处理⻚⾯展⽰
        for (BookInfo book:books){
            if (book.getStatus()==1){
                book.setStatusCN("可借阅");
            }else {
                book.setStatusCN("不可借阅");
            }
        }
        return books;
    }
}

//告诉 Spring 容器,“这个类需要被管理,请把它创建成一个 Bean”。
@Component
public class BookDao {
    public List<BookInfo> mockData() {
        List<BookInfo> books = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            BookInfo book = new BookInfo();
            book.setId(i);
            book.setBookName("书籍" + i);
            book.setAuthor("作者" + i);
            book.setCount(i * 5 + 3);
            book.setPrice(new BigDecimal(new Random().nextInt(100)));
            book.setPublish("出版社" + i);
            book.setStatus(1);
            books.add(book);
        }
        return books;
    }
}

先给类做**@Component**注解告诉Spring这两个类需要被管理,把他们创建成Bean,然后在BookService中需要new BooKDao()的地方做

@Autowired注解。做了这两步之后,每当需要BookService的getList()服务的时候,Spring会自动把BookDao的Bean注入到@Autowired标记过的地方。

上面这个过程就体现了依赖注入(Dependency Injection)

1.3 Bean的声明

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

1.4 Bean的注入

当一个Bean有多个实现类的时候,并且他们都有@Component或者其衍生注解的时候,Spring就不知道注入哪个了。

此时有三个注解可以用来解决这个问题:

  1. **@Primary:**当一个类标记了@Component或者其衍生注解的类添加@Primary注解的时候,Spring在注入Bean时会优先注入该类实现的Bean。
    在这里插入图片描述

  2. @Qualifier: 使用该注解配合@Autowired,可以指定当前注入哪个Bean。
    在这里插入图片描述

  3. **@Resource:**直接使用该注解标记注入处,不使用@Autowired。

在这里插入图片描述

@Resource与@Autowired的区别:

  1. @Autowired默认按照类型进行注入,而@Resource按照名称进行注入。
  2. @Autowired是Spring框架提供的注解,而@Resource是JDK提供的注解。

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

相关文章:

  • 学习路之TP6 --重写vendor目录下的文件(服务覆盖command---优点:命令前后一致)
  • PentestGPT 下载
  • 在ArcGIS中对图斑进行自上而下从左往右编号
  • 如何解决ChatGPTplus/pro o1/o3模型无法识别图片或者文件,限制次数?
  • 力扣——排序链表
  • 浅述WinForm 和 WPF 的前景
  • Docker生存手册:安装到服务一本通
  • Part2:基于国内源完成Kubernetes集群部署
  • k8s-dashboard
  • 【学习笔记】【C++】哪些函数不能是虚函数
  • Chart GPT、DeepSeek 辅助学习H3C网络工程师考试(一)
  • rsync 备份 clickhouse
  • 【AI论文】MM-Eureka:基于规则的大规模强化学习探索视觉“啊哈”时刻
  • P1591 阶乘数码
  • 12.16some pro about py model
  • 微软.NET框架下通信技术理解与实践
  • STM32U575RIT6单片机(二)
  • 机器学习扫盲系列(1) - 序
  • 【leetcode hot 100 114】二叉树展开为链表
  • uniapp-x 之useAttrs只读