Java-27 深入浅出 Spring - 实现简易Ioc-03 在上节的业务下手动实现IoC
点一下关注吧!!!非常感谢!!持续更新!!!
大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html
目前已经更新到了:
- MyBatis(已更完)
- Spring(正在更新…)
上节进度
上节完成了基本代码的编写,本节我们继续。本节将进行 IoC的实现。
IoC 实现
此时我们需要一个 Bean 的管理容器,当我们需要 new 对象的时候,可以直接从容器中获取出来。但是我们需要在程序启动的时候(当然也可以懒加载)就把这些对象初始化出来,所以我们需要 XML 来告诉容器需要加载什么内容。
IoC(Inversion of Control,控制反转)简介
控制反转(IoC)是一种设计原则,用于实现组件间的解耦,是面向对象编程中非常重要的概念之一。IoC的核心思想是将程序中对对象的控制权从调用方转移到框架或容器中,使得对象之间的依赖关系由容器来管理。
IoC 的特点
解耦
IoC通过将依赖的管理和创建责任交给容器,减少了模块之间的耦合性,增强了系统的可维护性和可扩展性。
动态依赖管理
容器根据配置或注解动态地将依赖注入到对象中,而不需要硬编码的依赖关系。
灵活性
对象的依赖可以在运行时动态修改,只需更改配置即可,不需要修改代码。
IoC 的应用场景
IoC被广泛应用于各种软件开发框架和项目中,以下是几个典型应用:
- Spring Framework:Spring框架使用IoC容器管理Bean的生命周期和依赖关系。开发者只需定义组件及其依赖,具体的实例化和依赖注入由Spring容器完成。
- Guice 和 Dagger:这些轻量级DI框架在Java项目中也很流行,提供了简单高效的依赖注入功能。
- 前端框架(如Angular):Angular中也实现了IoC,通过其依赖注入系统来管理组件和服务之间的依赖关系。
IoC 的优势
- 增强模块化:通过减少模块之间的直接依赖,促进模块化设计。
- 提高测试性:依赖注入可以方便地替换依赖对象,从而支持单元测试。
- 增强灵活性:通过配置或注解动态注入依赖,无需修改代码即可适应变化。
- 便于维护:解耦使得系统在增加或修改功能时影响最小。
IoC 的限制
- 学习曲线:初学者需要一定时间理解IoC和DI的概念。
- 运行时性能开销:IoC容器在运行时解析依赖关系可能会引入一些性能开销。
- 复杂性:在大型项目中,过度使用IoC可能导致配置和依赖关系变得复杂。
Resources
Resources 目录下
beans.xml
我们先编写一个 XML 来保存我们的 Bean 的信息:
<?xml version="1.0" encoding="UTF-8" ?>
<!-- BeanFactory 类会进行处理这块内容 -->
<beans><!-- WzkConnectionUtils 交给容器管理 --><bean id="wzkConnectionUtils" class="wzk.utils.WzkConnectionUtils"></bean><!-- 依赖了工具类 WzkConnectionUtils --><!-- id 是放入到容器中的名称 --><bean id="wzkAccountDao" class="wzk.dao.impl.JdbcWzkAccountDaoImpl"><!-- name是成员变量名字 ref是引用从容器中拿对象 --><property name="WzkConnectionUtils" ref="wzkConnectionUtils"/></bean><!-- 依赖了 WzkAccountDao --><bean id="wzkTransferService" class="wzk.service.impl.WzkTransferServiceImpl"><!-- name是成员变量名字 ref是引用从容器中拿对象 --><property name="WzkAccountDao" ref="wzkAccountDao"></property></bean>
</beans>
对应的内容截图如下所示:
注意:需要将 beans.xml 放置到 resources 目录下。
Proxy
BeanFactory
public class BeanFactory {private BeanFactory() {}/*** 全局容器 对象都存储到这里*/private static Map<String, Object> map = new HashMap<>();static {// 对 XML 进行处理,这里可以参考我们之前 手写的MyBatis的部分// 静态代码块 来进行初始化InputStream resourceAsSteam = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");SAXReader saxReader = new SAXReader();try {Document document = saxReader.read(resourceAsSteam);Element rootElement = document.getRootElement();List<Element> beanList = rootElement.selectNodes("//bean");for (Element element : beanList) {// 处理每个 Bean 元素String id = element.attributeValue("id");String clazz = element.attributeValue("class");// 反射拿到对象Class<?> aClass = Class.forName(clazz);Object object = aClass.newInstance();// 保存到容器中map.put(id, object);}List<Element> propertyList = rootElement.selectNodes("//property");for (Element element : propertyList) {// 处理每个依赖关系String name = element.attributeValue("name");String ref = element.attributeValue("ref");// 拿到父级节点 它下边的 property都是它的依赖Element parentElement = element.getParent();String parentId = parentElement.attributeValue("id");// 通过父级的 ID 拿到对象Object parentObject = map.get(parentId);// 拿到父级的所有方法 Get Set 等等Method[] methods = parentObject.getClass().getMethods();for (Method method : methods) {// 如果是 set 方法的话 我们调用就可以将它的依赖赋值给父级if (method.getName().equalsIgnoreCase("set" + name)) {method.invoke(parentObject, map.get(ref));}}// 记得更新容器的内容map.put(parentId, parentObject);}System.out.println("BeanFactory 初始化完毕 map:" + map);} catch (Exception e) {System.out.println("BeanFactory 初始化失败");e.printStackTrace();}}public static Object getBean(String id) {return map.get(id);}}
对应的截图如下所示:
Controller
WzkServlet
我们对 WzkServlet 进行一些修改:
@WebServlet(name="wzkServlet", urlPatterns = "/wzkServlet")
public class WzkServlet extends HttpServlet {// ========================== 2 ==========================// 由 BeanFactory 处理private WzkTransferService wzkTransferService = (WzkTransferService) BeanFactory.getBean("wzkTransferService");// =======================================================@Overrideprotected void doGet(javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse resp) throws javax.servlet.ServletException, IOException {System.out.println("=== WzkServlet doGet ===");// ======================= 1 =============================// 由于没有 Spring 的帮助 我们就需要手动去创建和维护依赖之间的关系// 组装 DAO DAO层依赖于 ConnectionUtils 和 DruidUtils// JdbcWzkAccountDaoImpl jdbcWzkAccountDaoImpl = new JdbcWzkAccountDaoImpl();// jdbcWzkAccountDaoImpl.setConnectionUtils(new WzkConnectionUtils());// 组装 Service// WzkTransferServiceImpl wzkTransferService = new WzkTransferServiceImpl();// wzkTransferService.setWzkAccountDao(jdbcWzkAccountDaoImpl);// ======================================================// 执行业务逻辑try {wzkTransferService.transfer("1", "2", 100);} catch (Exception e) {e.printStackTrace();System.out.println("=== transfer error ====");}resp.setContentType("application/json;charset=utf-8");resp.getWriter().print("=== WzkServlet doGet ===");}}
WzkServlet(2)
还有一种写法也是类似的,这样的处理方式也可以顺利执行的。
// ========================== 3 ==========================// 另一种方式 相同的private WzkTransferService wzkTransferService;@Overridepublic void init() throws ServletException {super.init();this.wzkTransferService = (WzkTransferService) BeanFactory.getBean("wzkTransferService");}// ======================================================
测试运行
我们运行代码之后,可以看到控制台如下所示:
BeanFactory 初始化完毕 map:{wzkTransferService=wzk.service.impl.WzkTransferServiceImpl@5dfdd67c, wzkAccountDao=wzk.dao.impl.JdbcWzkAccountDaoImpl@380d9fc0, wzkConnectionUtils=wzk.utils.WzkConnectionUtils@2d150354}
=== WzkServlet doGet ===
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
11月 18, 2024 6:24:24 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
transfer fromResult: 1 toResult: 1
对应的控制台结束如下所示:
查看结果
数据库的结果已经变化了,可以看到结果如下:
当然,刚才的代码打印的内容,也说明我们的代码是正常工作的。
(你可以打断点进行调试)
目前问题
我们虽然已经实现了简易的 IoC,但是对于当前业务来说,我们还需要对事务进行控制,此时需要我们实现一个事务的管理器,将采取和数据库一样,用 ThreadLocal 来进行控制。
相关文章:

Java-27 深入浅出 Spring - 实现简易Ioc-03 在上节的业务下手动实现IoC
点一下关注吧!!!非常感谢!!持续更新!!! 大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了: MyBatisÿ…...

kubernetes学习-使用metrics-server监控集群资源和查看日志
kubernetes学习-使用metrics-server监控集群资源和查看日志 一 、简介二、应用场景三、部署四、查看日志 一 、简介 Metrics Server 是一个用于 Kubernetes 集群的监控工具,它用于收集、存储和提供关于集群中各种资源的度量数据。Metrics Server 是 Kubernetes 中一…...

解决 Git Permission denied 问题
前言 push项目时出现gitgithub.com: Permission denied (publickey). fatal: Could not read from remote repository.Please make sure you have the correct access rights and the repository exists.出现这个问题表示你在尝试将本地代码推送到GitHub时,没有提供…...

CCNP_SEC_ASA 第三天作业
实验需求: ASA 使用列表放行 Outside 路由器到 DMZ 路由器的 WWW 流量并拒绝 Telnet 流量,当放行和拒绝流量匹配后产生日志通告。 提示:需要使能 ASA的日志功能和 DMZ路由器的 HTTP功能。 设备配置: ##此处展示各设备的配置&am…...

TypeError: Cannot read properties of null (reading ‘ce‘)
vue项目本地跑不起来,但是build之后能运行,本地报错 是因为你的vue版本不对,你的package可能是这样写的 这个表示你允许你的npm安装vue3的任意版本,但是build是按照这个版本来的,所以build之后能运行,本地运…...
AdminJS - 集成 MySQL 的现代化管理面板开发指南
AdminJS - 集成 MySQL 的现代化管理面板开发指南 MySQL 集成配置 首先需要安装必要的依赖: npm install adminjs adminjs/express express npm install adminjs/sequelize sequelize mysql2基础配置示例 const AdminJS require(adminjs) const AdminJSExpress …...

上传文件(vue3)
使用el-upload 先上传到文件服务器,生成url 然后点击确定按钮: 保存数据 <template><el-dialog top"48px" width"500" title"新增协议" :modelValue"visible" close"handleClose()">…...

【Win10 环境vscode配置boost】
文章目录 Boost exe版本windows环境安装vscode配置安装测试总结 Boost exe版本windows环境安装 这里不介绍boost源码安装,请自行网络搜索。本文要介绍的是window下单c文件(cpp),调用boost库的执行配置。不涉及多文件。 安装文件下…...

中间件 redis安装
redis官网地址:Redis - The Real-time Data Platform 环境 CentOS Linux release 7.9.2009 (Core) java version "17.0.12" 2024-07-16 LTS 1、通过压缩包安装redis 1,远程下载redis压缩包,或去官网下载:Downloads …...
[java] 简单的熔断器scala语言案例
failureRateInterval时间内如果addEx(错误)达到 maxFailuresPerInterval 次数,则fused方法返回true,表示触发熔断,进入冷却期coolingInterval,冷却期内fused方法返回true,冷却期过后进入下一个错误统计周期。 scala语言完成 imp…...
【java】序列化的种类和使用场景
文章目录 序列化概述什么是序列化?序列化的作用 Java内置序列化java.io.Serializable接口使用ObjectOutputStream和ObjectInputStream优缺点分析 自定义序列化实现Externalizable接口自定义序列化方法适用场景 第三方序列化框架KryoProtobuf (Google Protocol Buffe…...
Qt5与Qt6中的高DPI缩放属性解析
在Qt5中,高DPI缩放默认是禁用的。为了启用它,开发者需要设置Qt::AA_EnableHighDpiScaling应用程序属性。然而,在Qt6中,高DPI缩放默认是启用的,并且不能被禁用。这种变化使得开发者在处理高分辨率屏幕时更加方便&#x…...
Mac使用总结
Mac 常用快捷键 复制:Cmdc粘贴:Cmdv只粘贴文档: ShiftCmdv行首: Cmd<行尾:Cmd>鼠标处选中到行首:ShiftCmd<鼠标处选中到行尾:ShiftCmd>选中整行:上面两个命令组合鼠标处…...

【日期规则】EXCEl 自定义日期匹配规则,学习基础知识,自由匹配场景
excel 新建规则工具路径:开始 - 条件格式 - 新建规则 B$1TODAY() 注意:新建规则后,要点击 条件格式 - 管理规则 - 应用于 要选择规则应用范围 使用场景: excel 做进度管理当中可以查看当天的情况;每周的学习规划 或…...
苹果电脑可以安装windows操作系统吗?Mac OS X/OS X/macOS傻傻分不清?macOS系统的Java支持?什么是macOS的五大API法王?
苹果电脑可以安装windows操作系统吗? 先抛开虚拟机安装,苹果电脑可以安装Windows操作系统。苹果公司提供了一个名为Boot Camp的软件,它允许用户在Mac电脑上安装Windows操作系统。通过Boot Camp,用户可以在启动电脑时选择是要进入macOS还是Wi…...

芋道SpringBoot配置Maven、创建SpringBoot项目、创建Web接口、读取配置信息
🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 系列文章目录 第一章 芋…...

物理机内网穿透
前言: 本文主要讲述如何使用内网穿透以及其安全性。 将带领大家在公网上搭建几个常用靶场。 一,什么是内网穿透。 大多数情况下,我们的个人电脑都处于内网,即没有可公开访问的独立 IP 地址,因此其他内网用户找不到…...

Vue 3: 通过图片链接获取图片颜色,间接设置背景颜色
在现代Web开发中,动态获取和处理图像数据是一个常见的需求。例如,你可能希望自动提取一张图片的主色调,以便根据这些颜色进行UI主题调整或其他视觉效果的处理。本文将介绍如何在Vue 3项目中,通过一个图片链接获取图片的颜色信息。…...

opencv-python的简单练习
题目1.读取一张彩色图像并将其转换为灰度图。 import cv2 # 读取图片文件 img cv2.imread(./1.png)# 将原图灰度化 img_gray cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)# 输出图片 cv2.imshow(img,img) cv2.imshow(img_g,img_gray) # 进行阻塞 cv2.waitKey(0) 题目2:…...
如何使用生成式AI实现跨领域内容生成
文章目录 引言生成式AI的基本概念定义与分类技术发展现状 跨领域内容生成的技术实现数据准备模型选择与设计训练策略 应用案例分析教育培训新闻媒体文化创意产业 实践建议确定明确的目标构建合适的团队持续迭代改进遵守法律法规 结论 引言 在当今数字化时代,信息的…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...

路由基础-路由表
本篇将会向读者介绍路由的基本概念。 前言 在一个典型的数据通信网络中,往往存在多个不同的IP网段,数据在不同的IP网段之间交互是需要借助三层设备的,这些设备具备路由能力,能够实现数据的跨网段转发。 路由是数据通信网络中最基…...
接口 RESTful 中的超媒体:REST 架构的灵魂驱动
在 RESTful 架构中,** 超媒体(Hypermedia)** 是一个核心概念,它体现了 REST 的 “表述性状态转移(Representational State Transfer)” 的本质,也是区分 “真 RESTful API” 与 “伪 RESTful AP…...