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");
    // =======================================================

    @Override
    protected 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;
    @Override
    public 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.
1118, 2024 6:24:24 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
transfer fromResult: 1 toResult: 1

对应的控制台结束如下所示:
在这里插入图片描述

查看结果

数据库的结果已经变化了,可以看到结果如下:
在这里插入图片描述
当然,刚才的代码打印的内容,也说明我们的代码是正常工作的。
(你可以打断点进行调试)

目前问题

我们虽然已经实现了简易的 IoC,但是对于当前业务来说,我们还需要对事务进行控制,此时需要我们实现一个事务的管理器,将采取和数据库一样,用 ThreadLocal 来进行控制。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue使用pdfh5.js插件,显示pdf文件白屏

pdfh5&#xff0c;展示文件白屏&#xff0c;无报错 实现效果图解决方法(降版本)排查问题过程发现问题查找问题根源1、代码写错了&#xff1f;2、预览文件流的问题&#xff1f;3、pdfh5插件更新了&#xff0c;我的依赖包没更新&#xff1f;4、真相大白 彩蛋 实现效果图 解决方法…

【机器学习算法】——决策树之集成学习:Bagging、Adaboost、Xgboost、RandomForest、XGBoost

集成学习 **集成学习(Ensemble learning)**是机器学习中近年来的一大热门领域。其中的集成方法是用多种学习方法的组合来获取比原方法更优的结果。 使用于组合的算法是弱学习算法&#xff0c;即分类正确率仅比随机猜测略高的学习算法&#xff0c;但是组合之后的效果仍可能高于…

C/S软件授权注册系统(Winform+WebApi+.NET8+EFCore版)

适用软件&#xff1a;C/S系统、Winform桌面应用软件。 运行平台&#xff1a;Windows .NETCore&#xff0c;.NET8 开发工具&#xff1a;Visual Studio 2022&#xff0c;C#语言 数据库&#xff1a;Microsoft SQLServer 2012&#xff0c;Oracle 21c&#xff0c;MySQL8&#xf…

Big Model weekly | 第49期

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 01 Magnetic Preference Optimization: Achieving Last-iterate Convergence for Language Models Alignment 自我对弈方法在多个领域增强模型能力方面展现出了显著的成功。在基于人类反馈的强化学习&#xff0…

如何建设金融数据中心

目录 总则 概述 要求 基本原则 数据中心治理 概述 战略管控 战略规划 战略实施 延伸阅读 总则 概述 本文以描述金融数据中心的治理域内容为基础,从金融数据中心建设、运营及安全保障的角度出 发,逐一描述场地环境、网络通信、运行管理和风险管控等能力域的具体…

医学分割数据集B超图片肝脏分割数据集labelme格式271张1类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;271 标注数量(json文件个数)&#xff1a;271 标注类别数&#xff1a;1 标注类别名称:["liver"] 每个类别标注的框数&#xf…

Android:展锐T760平台camera PDAF调试

一、平台PDAF流程 目前展锐平台主要支持Shield PD Sensor、Dual PD Sensor 1、Shield PD Sensor Type1相位差和信心度结果直接从Sensor输出,不经过平台算法库。 Type2Sensor端抽取PD信息, 放在一块buffer输出, PDAF算法库算出相位差和信心度。 Type3Sensor端直接输出将带有…

MySQL的历史和地位

秋招之后&#xff0c;开始深入学习后端开发知识啦。把学到的东西分享给大家最开心啦。就从MySQL开始吧。 首先说一下MySQL的历史和地位。主要是看一下我们为什么要学习&#xff0c;而不是说让我们学什么我们就学什么。 地位 这张图是我从DB-Engines截取的2024年12月最新的数据…

鸿蒙项目云捐助第七讲鸿蒙App应用的首页推荐模块布局的实现

鸿蒙项目云捐助第七讲鸿蒙App应用的首页推荐模块布局的实现 最后设置首页的推荐模块&#xff0c;参考模板如下图所示。 一、首页热门推荐模块的实现 对于热门推荐模块&#xff0c;先有上面的小标题栏&#xff0c;这里的标题栏也有一个小图标&#xff0c;首先从“百度图库”中…

使用ENSP实现NAT(2)

一、NAT的类型 二、静态NAT 1.项目拓扑 2.项目实现 路由器AR1配置&#xff1a; 进入系统视图 sys将路由器命名为AR1 sysname AR1关闭信息中心 undo info-center enable 进入g0/0/0接口 int g0/0/0将g0/0/0接口IP地址配置为192.168.10.254/24 ip address 192.168.10.254 24进…

【1211更新】腾讯混元Hunyuan3D-1文/图生3D模型云端镜像一键运行

目录 项目介绍 显存占用 11月21 新增纹理烘焙模块Dust3R 烘焙相关参数&#xff1a; AutoDL云端镜像 启动说明 标准模型下载 【1212更新】腾讯混元Hunyuan3D-1文图生3D模型云端镜像一键运行 项目介绍 https://github.com/Tencent/Hunyuan3D-1 腾讯混元 3D 生成模型,支持…

PHP 应用 ImageMagick

ImageMagick是什么&#xff1f; ImageMagick是一款功能强大、跨平台的图像处理软件。它可以读取、转换和输出大量的图片格式&#xff0c;支持各种各样的图像处理操作&#xff0c;如调整大小、旋转、加水印、格式转换等。在PHP中使用ImageMagick&#xff0c;可以让我们在web应用…

OpenCV圆形标定板检测算法findGrid原理详解

OpenCV的findGrid函数检测圆形标定板的流程如下: class CirclesGridClusterFinder {CirclesGridClusterFinder(const CirclesGridClusterFinder&); public:CirclesGridClusterFinder

阿里云服务器手动搭建WordPress【官方文档注意事项】

这是官方文档 注意事项 先配LNMP&#xff0c;我的上一篇文章到这里发现&#xff0c;没有基于ubuntu的教程&#xff0c;所以创建服务器时选择centos在官方文档第四步“下载WordPress&#xff0c;并移动至网站根目录”中&#xff0c;首先它让cd /usr/share/nginx/html&#xff…

vue运行项目时local有显示 但是network却显示unavailable

问题描述 日常开发中 和后端本地调试时 后端需要使用你的本地去访问页面 可运行项目时会出现network显示unavailable的情况 解决方式 1.其实这只是vue脚手架对于ip地址获取的方式兼容上有一些问题 但其实是不影响ip访问本地的 你可以直接cmd内ipconfig去查看自己的ip然后…

Go项目-----Kubernetes使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言基本概念kubectl工具部署web服务生成镜像编写deployment 编写service启动服务 k8s部署mysql编写pvc编写pv编写service 部署redis集成部署mysql和redis 前言 这…

SpringCloud无介绍快使用,sentinel注解@SentinelResource的基本使用(二十三)

TOC 问题背景 从零开始学springcloud微服务项目 注意事项&#xff1a; 约定 > 配置 > 编码IDEA版本2021.1这个项目&#xff0c;我分了很多篇章&#xff0c;每篇文章一个操作步骤&#xff0c;目的是显得更简单明了controller调service&#xff0c;service调dao默认安装ngi…

紫光展锐5G融云方案,开启云终端新时代

近年来&#xff0c;云终端凭借便捷、高效、高性价比的优势正逐步在各行各业渗透。研究机构IDC的数据显示&#xff0c;2024上半年&#xff0c;中国云终端市场总体出货量达到166.3万台&#xff0c;同比增长22.4%&#xff0c;销售额29亿元人民币&#xff0c;同比增长24.9%&#xf…

基于卷积神经网络的垃圾分类系统实现(GUI应用)

1.摘要 本文主要实现了一个卷积神经网络模型进行垃圾图像分类&#xff0c;为了提高垃圾分类模型的准确率&#xff0c;使用使用Batch Normalization层、使用早期停止策略来防止过拟合等方法来优化模型&#xff0c;实验结果显示最终优化后的模型准确率较高90%左右。最终&#xf…

【51单片机】蜂鸣器快速上手

‌51单片机蜂鸣器是一种将电信号转换为声音信号的器件&#xff0c;在51单片机开发板中常用于产生按键音、报警音等提示信号‌。 ‌蜂鸣器类型‌&#xff1a;蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器。有源蜂鸣器内部自带振荡源&#xff0c;只需接上直流电压即可持续发声&…