Spring 的 IoC 和 DI 详解:从零开始理解与实践

Spring 的 IoC和 DI 详解:从零开始理解与实践

一、IoC(控制反转)

1、什么是 IoC?

IoC 是一种设计思想,它的核心是将对象的创建和管理权从开发者手中转移到外部容器(如 Spring 容器)。通过这种方式,开发者不再需要手动创建对象和管理它们之间的依赖关系,而是将这些任务交给 Spring 容器来完成。

举个例子
在传统的开发中,如果你需要一个 BookService 来调用 BookDao 的方法,你可能会直接在 BookService 中通过 new BookDao() 创建 BookDao 的实例。这种方式虽然简单,但会导致代码的耦合度很高,难以维护和扩展。

而使用 IoC 后,BookDao 的实例会由 Spring 容器创建,并自动注入到 BookService 中。开发者只需关注业务逻辑,无需关心对象的创建和依赖关系。

2、 IoC 的实现原理

IoC 的实现基于 Spring 容器。Spring 容器负责创建对象、管理对象的生命周期以及对象之间的依赖关系。开发者通过配置文件(如 XML 文件)或注解的方式,将类交给 Spring 容器管理。

3、示例代码

3.1创建类

package dao;public interface BookDao {void save();
}package dao.impl;import dao.BookDao;public class BookDaoImpl implements BookDao {@Overridepublic void save() {System.out.println("BookDao save...");}
}package service;import dao.BookDao;public interface BookService {void save();
}package service.impl;import service.BookService;
import dao.BookDao;public class BookServiceImpl implements BookService {private BookDao bookDao;public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}@Overridepublic void save() {System.out.println("BookService save...");bookDao.save();}
}

3.2 配置 Spring 容器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="bookService" class="service.impl.BookServiceImpl"><property name="bookDao" ref="bookDao"></property></bean><bean id="bookDao" class="dao.impl.BookDaoImpl"></bean>
</beans>

3.3 运行程序

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.BookService;public class Main {public static void main(String[] args) {// 创建 Spring 容器ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");// 从容器中获取 BookService 对象BookService bookService = (BookService) applicationContext.getBean("bookService");// 调用 save 方法bookService.save();}
}

4、运行效果

运行程序后,控制台会输出以下内容:

BookService save...
BookDao save...

运行效果讲解

  • Spring 容器会根据 applicationContext.xml 文件中的配置,创建 BookServiceImplBookDaoImpl 的实例。
  • BookDaoImpl 的实例由 Spring 容器创建并通过 setBookDao 方法注入到 BookServiceImpl 中。

二、DI(依赖注入)

1、什么是 DI?

DI 是 IoC 的一种实现方式,通过外部注入依赖对象,而不是在类内部创建依赖对象。这种方式使得依赖关系更加清晰,便于维护和测试。

2、DI 的实现方式

DI 的实现方式主要有以下几种:

构造函数注入:通过构造函数传递依赖对象。
Setter 注入:通过 Setter 方法注入依赖对象。
字段注入:直接在字段上注入依赖对象(需要使用注解)。

3、示例代码

3.1 使用 Setter 注入

package service.impl;import dao.BookDao;public class BookServiceImpl implements BookService {private BookDao bookDao;// 通过 Setter 方法注入依赖public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}@Overridepublic void save() {System.out.println("BookService save...");bookDao.save();}
}

3.2 配置 Spring 容器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="bookService" class="service.impl.BookServiceImpl"><property name="bookDao" ref="bookDao"></property></bean><bean id="bookDao" class="dao.impl.BookDaoImpl"></bean>
</beans>

3.3 运行程序

运行方式与 IoC 示例相同,代码如下:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.BookService;public class Main {public static void main(String[] args) {// 创建 Spring 容器ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");// 从容器中获取 BookService 对象BookService bookService = (BookService) applicationContext.getBean("bookService");// 调用 save 方法bookService.save();}
}

4 运行效果

运行程序后,控制台会输出以下内容:

BookService save...
BookDao save...

运行效果讲解

  • BookDaoImpl 的实例由 Spring 容器创建并通过 setBookDao 方法注入到 BookServiceImpl 中。
  • 依赖关系由容器管理,BookServiceImpl 不再直接依赖 BookDaoImpl 的具体实现。

三、Bean 的类型

1、Bean 的基础类型

1.1 name

可以设置别名,相当于 id 的作用,可以设置多个,后面的 ref 也可以引用 name 中的名字。

<bean id="bookdao" name="dao book se" class="dao.impl.BookDaoImpl"/>

1.2 scope

单例和非单例的设置,具体表现在重新创建时是否会刷新一个新的地址(默认为单例)。

<bean id="bookService" class="service.impl.BookServiceImpl" scope="prototype"/>

2、Bean 的实例化

2.1、构造方法实例化

通过反射的原理(直接通过class类进行)直接进行访问构造函数,无论是公共还是私有都能强制进行访问,不能设置实参,会报错

注:没有任何改变,系统自带就有,但不能添加一个有实参的构造,这样系统不会自动生成会报错

2.2、静态方法实例化

factory是一个中转站,通过改变xml中的获取方式类获取到factory中的new方法,本质还是在获取new中的对象

public static bookdao getOrderDao(){return new bookdaoimpl();
}
方式二:静态方法实例化<bean id="bookfactory" class="factory.factory1" factory-method="getOrderDao"></bean>

factory-method用于获取类中的这个方法

2.3、动态工厂

在这里插入图片描述

方法三:动态方法实例化
<bean id="bookfactory" class="factory.factory2"></bean>
<bean id="dao" factory-method="getOrderDao" factory-bean="bookfactory"></bean>

第一步先实例化对象,也就是第二行代码

第二部调用实例化的对象, factory-bean获取第一部的id名

2.4、factorybean

通过接口来实例化一些方法,减少xml中的操作

public class factory3 implements FactoryBean<bookdao>{@Overridepublic boolean isSingleton() {return  true;}@Overridepublic bookdao getObject() throws Exception {return new bookdaoimpl();}@Overridepublic Class<?> getObjectType() {return bookdao.class;}
}

isSingleton()设置是否单例

getObject() 获取返回对象

Type设置继承类型

方法四:factoryBean实例化
<bean id="factoryBean" class="factory.factory3"></bean>

3、Bean 的生命周期(两种方法)

3.1、直接创建

public void service(){System.out.println("book dao save.......");
}
public void init(){System.out.println("init");
}
public void destory(){System.out.println("destory");
}

需要在xml中加参数

<bean id="bookdao" name="dao book se" class="dao.impl.bookdaoimpl" init-method="init" destroy-method="destory"/>

init-method="init"设置初始化

destroy-method="destory"设置销毁

销毁的执行需要程序中进行close关闭后才能运行

ClassPathXmlApplicationContext cts = new ClassPathXmlApplicationContext("application.xml");
bookdao bookdao = (bookdao)cts.getBean("bookdao");
bookdao.service();
cts.close();

更改了ApplicationContext为ClassPathXmlApplicationContext

增加了cts.close();

3.2、接口创建实现

public class bookdaoimpl implements dao.bookdao, InitializingBean, DisposableBean {public void service(){System.out.println("book dao save.......");}@Overridepublic void destroy() throws Exception {System.out.println("destory.........");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("init........");}
}

实现了

InitializingBean, DisposableBean 两个接口

四、注入类型

1、Setter 注入

1.1 引用类型

通过 Setter 方法注入引用类型

public class BookServiceImpl {private BookDao bookDao;public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}
}
<bean id="bookService" class="service.impl.BookServiceImpl"><property name="bookDao" ref="bookDao"></property>
</bean>

ref用于设置这里的名字,name跟类中的名字相同

1.2 简单类型

通过 Setter 方法注入简单类型。

public class BookDaoImpl {private String databaseName;private int connectionNum;public void setDatabaseName(String databaseName) {this.databaseName = databaseName;}public void setConnectionNum(int connectionNum) {this.connectionNum = connectionNum;}
}
<bean id="bookDao" class="dao.impl.BookDaoImpl"><property name="databaseName" value="mysql"></property><property name="connectionNum" value="666"></property>
</bean>

value设置里面的值,没有顺序之分

2、构造器注入

2.1 引用类型

通过构造函数注入引用类型。

public class BookServiceImpl {private BookDao bookDao;public BookServiceImpl(BookDao bookDao) {this.bookDao = bookDao;}
}
<bean id="bookService" class="service.impl.BookServiceImpl"><constructor-arg name="bookDao" ref="bookDao"></constructor-arg>
</bean>

2.2 简单类型

通过构造函数注入简单类型。

public class BookDaoImpl {private String databaseName;private int connectionNum;public BookDaoImpl(String databaseName, int connectionNum) {this.databaseName = databaseName;this.connectionNum = connectionNum;}
}
<bean id="bookDao" class="dao.impl.BookDaoImpl"><constructor-arg name="databaseName" value="mysql"></constructor-arg><constructor-arg name="connectionNum" value="666"></constructor-arg>
</bean>

2.3命名的其他操作

name的命名可能耦合度过高

1、采取type=“” 类型来进行确定

2、采取index=""位置来进行确定

在这里插入图片描述

3、自动注入

在xml中进行配置直接进行注入

<bean class="com.itheima.dao.impl.BookDaoImpl"/>
<!--autowire属性:开启自动装配,通常使用按类型装配-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>

autowire一般情况使用bytype按类型

当有两个名字的情况进行按名字,名字取决于dao中的private类型

注意:setter类型不能够忘记,不然会报错
在这里插入图片描述

4、集合注入

通过 XML 配置注入集合类型。

public class BookDaoImpl {private int[] array;private List<String> list;private Set<String> set;private Map<String, String> map;private Properties properties;// Getter 和 Setter 方法
}
<bean id="bookDao" class="dao.impl.BookDaoImpl"><property name="array"><array><value>100</value><value>200</value><value>300</value></array></property><property name="list"><list><value>itcast</value><value>itheima</value></list></property><property name="set"><set><value>itcast</value><value>itheima</value></set></property><property name="map"><map><entry key="country" value="china"/><entry key="province" value="henan"/></map></property><property name="properties"><props><prop key="country">china</prop><prop key="province">henan</prop></props></property>
</bean>

五、总结

IoC 和 DI 是 Spring 框架的核心概念,它们的主要作用是降低代码的耦合度,提高代码的灵活性和可维护性。

  • IoC:通过将对象的创建和管理交给 Spring 容器,开发者只需关注业务逻辑。
  • DI:通过依赖注入的方式,使得依赖关系更加清晰,便于维护和测试。

在实际开发中,合理使用 IoC 和 DI 能够显著提高代码的质量和可维护性。希望这篇博客能够帮助你更好地理解和应用 Spring 的 IoC 和 DI!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/76265.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JVM基础架构:内存模型×Class文件结构×核心原理剖析

&#x1f680;前言 “为什么你的Java程序总在半夜OOM崩溃&#xff1f;为什么某些代码性能突然下降&#xff1f;一切问题的答案都在JVM里&#xff01; 作为Java开发者&#xff0c;如果你&#xff1a; 对OutOfMemoryError束手无策看不懂GC日志里的神秘数字好奇.class文件如何变…

.DS_Store文件泄露、.git目录泄露、.svn目录泄露漏洞利用工具

&#x1f409;工具介绍 一款图形化的 .DS_Store文件泄露、.git目录泄露、.svn目录泄露漏洞利用工具。 &#x1f3af;使用 本工具使用Python3 PyQt5开发&#xff0c;在开始使用前&#xff0c;请确保已经安装了相关模块&#xff1a; pip3 install -r requirements.txt -i ht…

为何在 FastAPI 中需要允许跨域访问(CORS)?(Grok3 回答)

prompt: 你是一个文笔流畅、专业性极强的技术博客博主&#xff0c;你将结合具体的例子和实际代码解释写一篇为何后端选择fastapi框架时&#xff0c;需要允许跨域访问。 为何在 FastAPI 中需要允许跨域访问&#xff08;CORS&#xff09;&#xff1f; 在现代 Web 开发中&#xf…

JDK8前后日期(计算两个日期时间差-高考倒计时)

JDK8之前日期、时间 Date SimpleDateFormat Calender JDK8开始日期、时间 LocalDate/LocalTime/LocalDateTime ZoneId/ZoneDateTIme Instant-时间毫秒值 DateTimeFormatter Duration/Period

Gerapy二次开发:用户管理专栏主页面开发

用户管理专栏主页面开发 写在前面用户权限控制用户列表接口设计主页面开发前端account/Index.vuelangs/zh.jsstore.js后端Paginator概述基本用法代码示例属性与方法urls.pyviews.py运行效果总结欢迎加入Gerapy二次开发教程专栏! 本专栏专为新手开发者精心策划了一系列内容,旨…

关于Spring MVC中传递数组参数的详细说明,包括如何通过逗号分隔的字符串自动转换为数组,以及具体的代码示例和总结表格

以下是关于Spring MVC中传递数组参数的详细说明&#xff0c;包括如何通过逗号分隔的字符串自动转换为数组&#xff0c;以及具体的代码示例和总结表格&#xff1a; 1. 核心机制 Spring MVC支持直接通过逗号分隔的字符串将请求参数自动转换为数组&#xff08;String[]、int[]等&…

大模型学习七:‌小米8闲置,直接安装ubuntu,并安装VNC远程连接手机,使劲造

一、说明 对于咱们技术人来说&#xff0c;就没有闲的蛋疼的时候&#xff0c;那不是现在机会来了 二、刷机器准备 1、申请解锁手机 申请解锁小米手机https://www.miui.com/unlock/download.html 下载工具&#xff0c;安装下面的步骤来&#xff0c;官网不欺人吧 打开开发者工…

repo安装配置

1.安装属性 以下配置方式二选一进行安装 1.1全局级别配置 1. 安装 repo 工具 在终端中输入以下命令以下载 repo 工具&#xff1a; curl https://storage.googleapis.com/git-repo-downloads/repo > /usr/bin/repo chmod ax /usr/bin/repo 1.2用户级别配置 1. 安装 r…

Go 语言数据类型

Go 语言数据类型 概述 Go 语言(也称为 Golang)是一种静态强类型、编译型、并发型、具有垃圾回收功能的编程语言。自2009年发布以来,Go 语言因其简洁的语法、高效的执行速度和强大的并发处理能力而广受欢迎。本文将详细介绍 Go 语言中的数据类型,帮助读者更好地理解和掌握…

C# 看门狗策略实现

using System; using System.Threading;public class Watchdog {private Timer _timer;private volatile bool _isTaskAlive;private readonly object _lock new object();private const int CheckInterval 5000; // 5秒检测一次private const int TimeoutThreshold 10000; …

Font Awesome Web 应用图标

1. 什么是 Font Awesome Web 应用图标 Font Awesome Web 应用图标是 Font Awesome 图标库中与 Web 开发相关的子集&#xff0c;适用于界面设计、用户交互和功能标识。 定义与作用 定义&#xff1a;这些图标包括导航&#xff08;如“主页”&#xff09;、操作&#xff08;如“…

如何实现H5端对接钉钉登录并优雅扩展其他平台

如何实现H5端对接钉钉登录并优雅扩展其他平台 钉钉H5登录逻辑后端代码如何实现&#xff1f;本次采用策略模式工厂方式进行定义接口确定会使用的基本鉴权步骤具体逻辑类进行实现采用注册表模式&#xff08;Registry Pattern&#xff09;抽象工厂进行基本逻辑定义具体工厂进行对接…

STM32F103C8T6单片机开发:简单说说单片机的外部GPIO中断(标准库)

目录 前言 如何使用STM32F1系列的标准库完成外部中断的抽象 初始化我们的GPIO为输入的一个模式 初识GPIO复用&#xff0c;开启GPIO的复用功能时钟 GPIO_EXTILineConfig和EXTI_Init配置外部中断参数 插入一个小知识——如何正确的配置结构体&#xff1f; 初始化中断&#…

【自然语言处理】深度学习中文本分类实现

文本分类是NLP中最基础也是应用最广泛的任务之一&#xff0c;从无用的邮件过滤到情感分析&#xff0c;从新闻分类到智能客服&#xff0c;都离不开高效准确的文本分类技术。本文将带您全面了解文本分类的技术演进&#xff0c;从传统机器学习到深度学习&#xff0c;手把手实现一套…

Java Lambda与方法引用:函数式编程的颠覆性实践

在Java 8引入Lambda表达式和方法引用后&#xff0c;函数式编程范式彻底改变了Java开发者的编码习惯。本文将通过实战案例和深度性能分析&#xff0c;揭示如何在新项目中优雅运用这些特性&#xff0c;同时提供传统代码与函数式代码的对比优化方案。 文章目录 一、Lambda表达式&a…

剑指offer经典题目(三)

目录 动态规划入门 二进制运算 链表相关 动态规划入门 题目1&#xff1a;一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法&#xff08;先后次序不同算 不同的结果&#xff09;。OJ地址 简单图示如下。 题目分析&#…

【每日随笔】丛林法则 ( 弱肉强食 | 适者生存 | 资源有限稀缺 | 没有道德约束 | 自发性与无序性 | 丛林法则映射 - 资源分配 与 社会分层 )

文章目录 一、丛林法则1、弱肉强食2、适者生存3、资源有限稀缺4、没有道德约束5、自发性与无序性6、丛林法则映射 - 资源分配 与 社会分层 一、丛林法则 丛林法则 是 在 资源有限 的环境中 , 竞争 是生存的基础 , 弱肉强食 , 适者生存 , 且过程 不受道德约束 ; 丛林法则 在 自…

【含文档+PPT+源码】基于小程序的智能停车管理系统设计与开发

项目视频介绍&#xff1a; 毕业作品基于小程序的智能停车管理系统设计与开发 课程简介&#xff1a; 本课程演示的是一款基于小程序的智能停车管理系统设计与开发&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;…

Navicat连接远程PostGreSQL失败

问题描述 使用本地Navicat连接Windows远程服务器上部署的PostGreSQL数据库时,出现以下错误: 解决方案 出现以上报错信息,是因为PostGreSQL数据库服务尚未设置允许客户端建立远程连接。可做如下配置, 1. 找到PostGreSQL数据库安装目录下的data子文件夹,重点关注:postgres…

【Linux】jumpserver开源堡垒机部署

JumpServer 安装部署指南 本文档详细记录了 JumpServer 安装部署的过程、核心脚本功能说明以及后续管理使用提示&#xff0c;方便运维人员快速查阅和二次安装。 1. 前提条件 操作系统要求&#xff1a; 仅支持 Linux 系统&#xff0c;不支持 Darwin&#xff08;macOS&#xff0…