SpringBoot入门-(2) Spring IOC机制【附实例代码】

SpringBoot入门-(2) Spring IOC机制

Spring

Spring是一个当前主流的轻量级的框架,发展到形状已经不仅仅是一个框架,而是形成以Spring为基础的生态圈,如(Spring Boot,Spring Cloud,Spring Security等)

Spring 两大核心技术

  • 控制反转(IoC)
  • 面向切面编程(AOP)

本文先介绍其一

控制反转(IoC/DI)

依赖注入(DI:Dependency Injection ):Spring通过创建容器的方式,来负责对象的创建、对象和对象之间关系的维护等

动机

在面向对象的系统设计中,底层的业务逻辑是由多个对象组成,对象之间通常存在复杂的联系,导致系统的耦合度很高,例如:

public class UserServiceImp implements UserService{private UserDao userdao = new UserDaoImp();...}

上述UserServiceImp类实现UserService接口,其中创建的私有成员变量是通过UserDaoImp类创建出来的实例。

UserDaoImp的业务逻辑产生变化或出现错误,都有可能需要修改UserServiceImp的代码,所谓产生了"牵一发而动全身"的系统高耦合度。

不难发现,系统越庞大,对象关系越复杂,系统耦合度越高,导致系统维护愈发困难。

因此,Spring横空出世,解决对象之间耦合度过高的问题。后来从产品发展为生态圈。

概念

究竟什么是控制反转?

先看下图:

在这里插入图片描述
首先是左图的情况,假设其他一个齿轮需要修改或不转动,都会导致其他的齿轮停止工作,这称为高耦合度。而右图,齿轮之间不存在依赖关系,工作相对独立,不会影响到其他齿轮的正常工作。这表现的就是"控制反转"的基本思想:

借助于“第三方”实现具有依赖关系的对象之间的解耦

齿轮之间的传动全部依靠“第三方”了, 全部对象的控制权全部上缴给“第三方”IOC容器,主动创建变为了被动注入, 这就是“控制反转”(依赖注入)这个名称的由来

代码

首先创建Maven项目(传送门:SpringBoot入门-(1) Maven【概念+流程】-CSDN博客),pom.xml文件导入相关spring依赖,包括测试依赖:

    <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>test</scope></dependency></dependencies>

注意,这里没有定义依赖的版本,是通过父项目统一管理版本号

without Spring

我们先用常规的MVC架构实现一些简单逻辑,后面对比Spring架构就可以明显发现其优势和作用。

首先我们实现一个非常简易的商品存入数据库的逻辑:

在这里插入图片描述
部分代码如下:

  • ProductDaoImpl

    package com.example.Dao;import com.example.Dao.ProductDao;
    import com.example.entity.Product;public class ProductDaoImpl implements ProductDao {//这里是模拟商品存入,并没有真正存入数据库@Overridepublic void saveProduct(Product product) {System.out.println("保存商品信息");System.out.println(product.toString());}
    }
    
  • ProductServiceImpl

    package com.example.Service;
    import com.example.entity.Product;
    import com.example.Dao.*;public class ProductServiceImpl implements ProductService{private ProductDao productDao =  new ProductDaoImpl();//其他业务逻辑,如检查是否合法等@Overridepublic void saveProduct(Product product) {productDao.saveProduct(product);}
    }
    

可以看到在ProductServiceImpl中,我们通过new的方式创建实例对象并赋值给成员变量

测试代码:

test目录底下进行测试:

package com.example.Service;import com.example.entity.Product;
import org.junit.jupiter.api.Test;public class ProductServiceTest { //如果 Calculator 类和测试类处于相同的包或者符合 Java 的包访问规则,那么测试类就可以直接访问 ProductServiceImpl 类。@Testpublic void testSaveProduct() {ProductService productService = new ProductServiceImpl();productService.saveProduct(new Product(0, "test",12.7));}
}

可以看到控制台输出信息:
在这里插入图片描述

with spring

我们现在使用spring框架实现相同的功能

  • 方式一:配置文件

首先新建spring的配置文件,如图:
在这里插入图片描述

命名为applicationContext,可以看到文件中已经存在默认的内容(默认生成的XML文件的NameSpace,<bean>就是关键的标签。

容器中创建对象,本质就是在文件中配置一个bean

<beans></beans>中间添加我们想要创建的对象及注入依赖

    <bean id="productDao" class="com.example.Dao.ProductDaoImpl"/><bean id="productService" class="com.example.Service.ProductServiceImpl"><property name="productDao" ref="productDao"/></bean>

容器通过com.example.Dao.ProductDaoImpl类创建id为productDao的对象

对象属性的赋值通过<property>标签,需要在com.example.Service.ProductServiceImpl提供对应的setter方法:

    public void setProductDao(ProductDaoImpl productDao) {this.productDao = productDao;}

下一步,在测试程序中创建容器,并获取指定对象进行测试。

public class ProductServiceTest {//如果 Calculator 类和测试类处于相同的包或者符合 Java 的包访问规则,那么测试类就可以直接访问 ProductServiceImpl 类。@Testpublic void testSaveProduct() {ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");ProductService productService = (ProductService) ac.getBean("productService");productService.saveProduct(new Product(0, "test",12.7));}
}

上述代码中,我们先创建了容器,然后根据xml文件中的配置获取对象,返回的类型是Object,注意转换类型。

观察到上述两种方式,spring将层与层之间的联系解耦,可以比较一下下面两段代码:

//解耦前
private ProductDao productDao =  new ProductDaoImpl();//spring
private ProductDao productDao;
//在配置文件中注入依赖
<bean id="productService" class="com.example.Service.ProductServiceImpl"><property name="productDao" ref="productDao"/>
</bean>

这样,我们在"更换齿轮"的时候就不用去修改Service层的代码,修改配置文件即可。(注意,配置文件依赖注入一定要在相应的地方添加setter方法,底层会进行调用)

  • 方式二: 注解实现IOC
  1. 注解+配置

当我们的项目很大的时候,使用配置文件就会出现问题,配置文件信息内容过大让人眼花缭乱,所以spring提供了注解的方式。

在这里插入图片描述
根据注解,我们可以把配置文件中的:

<bean id="productDao" class="com.example.Dao.ProductDaoImpl"/>

等效为:

@Repository("productDao")
//如果不给注解起名字,默认的名字为类名(首字母小写)
public class ProductDaoImpl implements ProductDao {//这里是模拟示范@Overridepublic void saveProduct(Product product) {System.out.println("保存商品信息");System.out.println(product.toString());}
}

Spring 默认不使用注解装配 Bean,因此我们需要在 Spring 的 XML 配置中,通过**context:component-scan** 元素开启 Spring Beans的自动扫描功能

<context:component-scan base-package="com.example.*"></context:component-scan>

其中base-package是你希望自动扫描的路径。

Bean的自动装配

使用@AutoWired注解实现自动装配,如:

public class ProductServiceImpl implements ProductService{@Autowiredprivate ProductDao productDao;
  1. 全注解

不使用spring配置文件,而是进行全注解开发,因此我们需要使用注解写一个配置类实现和annotation.xml的功能。

在config/目录下创建类文件:

@Configuration
@ComponentScan("com.example")
public class SpringConfig {
}

对应的测试代码:

    @Testpublic void testSaveProduct() {ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);ProductService productService = ac.getBean("productService", ProductService.class);

当然也可以在配置类中使用@Bean标签

@Configuration
@ComponentScan("com.example")
public class SpringConfig {@Bean(name = "productService")public ProductServiceImpl creat(){return new ProductServiceImpl();}
}

对应的测试代码修改一句即可:

ProductService productService = ac.getBean(ProductService.class);

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

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

相关文章

备赛蓝桥杯之第十六届模拟赛3期职业院校组

提示&#xff1a;本篇文章仅仅是作者自己目前在备赛蓝桥杯中&#xff0c;自己学习与刷题的学习笔记&#xff0c;写的不好&#xff0c;欢迎大家批评与建议 由于个别题目代码量与题目量偏大&#xff0c;请大家自己去蓝桥杯官网【连接高校和企业 - 蓝桥云课】去寻找原题&#xff0…

【AI大模型】提示词(Prompt)工程完全指南:从理论到产业级实践

【AI大模型】提示词&#xff08;Prompt&#xff09;工程完全指南&#xff1a;从理论到产业级实践 一、Prompt 提示词介绍&#xff1a;AI的“密码本” 1. Prompt的底层定义与价值 本质&#xff1a;Prompt是人与AI模型的“协议语言”&#xff0c;通过文本指令激活模型的特定推理…

Excel 小黑第12套

对应大猫13 涉及金额修改 -数字组 -修改会计专用 VLOOKUP函数使用&#xff08;查找目标&#xff0c;查找范围&#xff08;F4 绝对引用&#xff09;&#xff0c;返回值的所在列数&#xff0c;精确查找或模糊查找&#xff09;双击填充柄就会显示所有值 这个逗号要中文的不能英…

基于Spring Boot的冷链物流系统的设计与实现的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

python环境集成整理

接口测试过程中&#xff0c;可能会切换测试环境&#xff0c;通过配置相关信息修改 设计思路&#xff1a; 1、 准备各个环境配置文件信息&#xff0c;包括http、common 、redis、db 2、创建不同环境配置信息 测试环境&#xff1a;env_test.yml、 预生产环境:env_prepro.yml、生产…

动平衡仿真程序设计

以下是针对动平衡振动信号分析的模块扩展方案&#xff0c;基于原有信号发生器架构进行增强&#xff1a; 一、动平衡专用信号生成器 // UnbalanceVibrationGenerator.h #pragma once #include "SignalGenerator.h" #include <vector>class UnbalanceVibration…

牛客周赛85 题解 Java ABCDEFG

A小紫的均势博弈 判断输入的 n 是奇数还是偶数 import java.io.*; import java.math.*; import java.util.*;public class Main {static IoScanner sc new IoScanner();static final int mod(int) (1e97);static void solve() throws IOException {int nsc.nextInt();if(n%2…

python——UI自动化(1) selenium之介绍和环境配置

一、selenium介绍 selenium是一个第三方库&#xff0c;python有很多库&#xff1b; 1、什么是ui自动化? 通过模拟手工操作用户ui页面的方式&#xff0c;用代码去实现自动化操作和验证的行为。 2、ui自动化的优点&#xff1f; &#xff08;1&#xff09;解决重复性的功能测…

Can通信流程

下面给出一个更详细的 CAN 发送报文的程序流程说明&#xff0c;结合 HAL 库的使用及代码示例&#xff0c;帮助你了解每一步的具体操作和内部原理。 一、系统与外设初始化 1.1 HAL 库初始化 在 main() 函数开头&#xff0c;首先调用 HAL 库初始化函数&#xff1a; HAL_Init()…

15 数据结构及算法应用

15 数据结构及算法应用 15.1 算法策略区分 15.1.1、分治法 特征:把一个问题拆分成多个小规模的相同子问题&#xff0c;一般可用递归解决。 经典问题:斐波那契数列、归并排序、快速排序、矩阵乘法、二分搜索、大整数乘法、汉诺塔。 15.1.2、贪心法 (一般用于求满意解) …

基于大模型的唇裂手术全流程预测与应用研究报告

目录 一、引言 1.1 研究背景与意义 1.2 研究目标与内容 二、唇裂相关医学知识概述 2.1 唇裂的定义、分类与发病原因 2.2 唇裂对患者生理与心理的影响 2.3 传统唇裂治疗方法与局限性 三、大模型技术原理与应用基础 3.1 大模型概述 3.2 适用于唇裂预测的大模型类型及特…

环境变量设置异常导致UOS文件管理器无法正常运行

编译QT5.15.2&#xff0c;与UOS20.9的QT依赖冲突 现象原因解决方法 现象 重启系统后UOS桌面变成黑色&#xff0c;没有任何图标&#xff0c;任务栏的应用本来是有预览的&#xff0c;但也变得不可用。 原因 找了很久&#xff0c;查到原来是dde-file-manager未能正常启动。直接…

《认知觉醒》改变的核心方法论

《认知觉醒》改变的核心方法论 一、认知觉醒的核心目标 改变 → 提升能力 → 获得更好生活 二、大脑运作机制 脑区运算速度作用特点本能脑1.1亿次/秒自动化反应&#xff0c;能量消耗低情绪脑1.1亿次/秒情感驱动型决策​理智脑​40次/秒战略指挥官角色 关键差异&#xff1a…

Python中的字典:深度解析与应用实践

一、字典的本质与特性 Python字典&#xff08;Dictionary&#xff09;是以**键值对&#xff08;Key-Value Pair&#xff09;**形式存储数据的无序集合&#xff0c;使用大括号{}定义。其核心特性包括&#xff1a; 快速查找&#xff1a;基于哈希表实现&#xff0c;通过键&#…

【蓝桥杯python研究生组备赛】005 数学与简单DP

题目1 01背包 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入格式 第一行两个整数&a…

2024年国赛高教杯数学建模E题交通流量管控解题全过程文档及程序

2024年国赛高教杯数学建模 E题 交通流量管控解题 原题再现 随着城市化进程的加快、机动车的快速普及&#xff0c;以及人们活动范围的不断扩大&#xff0c;城市道路交通拥堵问题日渐严重&#xff0c;即使在一些非中心城市&#xff0c;道路交通拥堵问题也成为影响地方经济发展和…

穿越是时空之门(java)

emm&#xff0c;之前做过一道类似的题目&#xff0c;但是这次又忘了 一开始的错误代码 package Lanqiao;import javax.swing.plaf.synth.SynthTextAreaUI; import java.math.BigInteger;/*** author zb* date2025/3/19 21:33*/ public class L19701 {public static void main…

npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本的处理方法

1、安装了node.js后&#xff0c;windows powershell中直接输入npm&#xff0c;然后就报错 2、出现原因&#xff1a;权限不够 系统禁用了脚本的执行&#xff0c;所以我们在windows powershell输入npm -v的时候&#xff0c;就会报上面的错误。 3、解决 Set-ExecutionPolicy Un…

蓝桥杯单片机之AT24C02(基于自己对AT24C02的学习和理解)

一、先用抽象法说明原理&#xff0c;让原理变得简单易懂&#xff1a; 1、向AT24C02写入数据&#xff1a; 有个关系户&#xff0c;他想安排自己的儿子进某个大厦里某个楼层的公司&#xff0c;那么他就要先找到这个公司的地址&#xff0c;然后再找到该公司是第几楼&#xff0c;最…

Java面试易忽略知识点

1. CompletableFuture中thenApply()与thenCompose()的区别 考察点&#xff1a;组合式异步编程 解析&#xff1a; ​**thenApply()**&#xff1a;接收前序任务结果&#xff0c;返回普通对象&#xff08;同步转换&#xff09;&#xff0c;适用简单数据处理。​**thenCompose()*…