ioc spring 上机案例_抛开Spring去理解IOC思想 - 原来IOC容器这么简单

e213f1c2389efba945041169467a78c9.png
  • 很多小伙伴们看到标题可能就会想到抛开Spring就不会存在IOC思想了,其实不然在接下来的文章中就会讲述到。
  • 很多小伙伴在理解IOC的时候通常会和Spring放到一起去学习,首先呢Spring设计的非常之巧妙而且里面包含了很多除去IOC的其他功能。这样会导致我们在Spring的基础去理解IOC就变得很困难。很难抓住其核心思想。
  • 所以本文的标题的含义就是单纯的去理解IOC思想,然后通过自定义的IOC去加深对IOC的理解。
  • 看完本文之后再去理解Spring中的IOC其实思想是一致的,只是实现上有些出入。毕竟Spring是大神们经过深思熟虑后的成果。

736080abc4d230c5da053fd6611aa3f1.png

传统的思想(没有IOC容器的情况下)

在没有IOC容器的情况下,如果我们需要某个类具体的操作如下所示:

2e54bd39cd733da716006f07f301490a.png


传统的Bean创建

  1. 程序员对A进行了主动的使用(new)即创建了A类,A类中又依赖B类然后在对B类进行创建
  2. 创建对象的权利现在是程序员手上需要哪个类就会对那个类进行创建
  3. B类是由于程序员调用了A类有对B类的依赖随着而创建
  4. 总之就是自己动手丰衣足食,没有借助任何中间产物。

优点

  • 很直接的一个优点就是简单,我们需要什么就去创建什么,在程序员的角度上也是比较直观容易理解的。

缺点

  • Bean之间的协调关系是由程序内部代码来控制的即通过New关键字与我们的业务代码进行了强耦合。
  • 没有对Bean进行管理。
  • 对Bean没有进行统一的管理和配置。

IOC思想

首先在这里强调一下IOC不是Spring提出来了,在Spring之前就已经有人提出了IOC思想,只不过在Spring之前都是偏理论化没有一个具体的落地方案,Spring在技术层面把IOC思想体现的淋漓尽致。

什么是IOC(Inversion of controller)

  • IOC是一种思想,而不是一个技术的实现。
  • 主要的描述是在软件开发的领域对象的创建和管理的问题。
  • 上述我们了解了传统的开发模式,我们在来看看如果有IOC的思想下程序员是如何使用对象的。

0e77540fb6b5ece29295a5b5888524ea.png

从上图可知:

  • 程序员只需要告诉IOC自己需要那个Bean。就不需要关系该Bean创建的细节已经该Bean的相关依赖。这一切IOC容器已经帮你做好了。
  • 凡事有得必有失: 这个过程中我们失去了创建Bean的权利。
  • 了解了基本的使用后,有人说IOC就是控制反转,讲到这里你还没将控制反转?好!别急接下来就是细讲我们常说的控制反转。

控制反转

在理解控制反转之前我们首先要清楚控制是指什么? 反转又反转了什么?

  • 控制: 指的就是我们上述说的我们失去的权利(创建对象的创建,或者说控制对象的权利)
  • 反转: 指的是控制权的转变。在没有IOC的容器上我们程序员想创建谁就创建谁的权利。在IOC容器下程序员就只能委屈巴巴的向IOC容器索取对象。创建对象的权利由程序员到IOC容器手里了。

IOC解决了什么问题?

  • 其实就是解决了对象之间的耦合问题。
  • 我们不需要在通过New关键字来创建对象,而是从容器中获取达到一种松耦合的目的。
  • 同时IOC容器也方便管理容器内的所有Bean对象。所谓的Bean的生命周期。

IOC和DI的区别

将到IOC肯定会有人想到DI(Dependancy Injection)依赖注入,那这两者有什么不同和相同呢?

相同点

  • IOC和DI描述的都是同一件事情(对象的实例化以及维护对象与对象已经的依赖关系)

不同点

  • 首先IOC是一种思想,而DI是一种具体的技术实现手段。
  • IOC是站着对象的角度上对象的实例化以及管理从程序员的手里交给了IOC容器
  • DI是站着容器的角度的上会把对象的依赖的其他对象注入到容器中,上述案例中的A类依赖B类IOC容器不仅仅将A类放到容器中还需要将其依赖的B类也一并加载到IOC容器中。

如何自定义实现一个IOC容器

  • 小伙伴们看到这里其实对IOC容器已经有了一定的了解。那如果在面试的过程中面试官问你如何实现一个自定义的IOC容器。你可以讲出的具体思路嘛? 可以先想一想在继续往下看,看看是不是和自己的想发不谋而合。
  • 思路大致如下所示:

0b0af7422f6de1338ae0e371d913ccf8.png
  • 想必大家都有自己的一定的理解,可能做法比较简单,但是对于理解IOC容器而已其实已经足够了。如果想更加准确或者深入了解其底层实现,可以按照这个思路去看Spring的相关源码实现,相信你一定会得心应手。

小案例

  • 我们通过一个小案例来写我们的IOC容器
  • 我们经常购物,我们可以把购物简单的理解成下单和减库存两个操作。
  • 有同学会问为什么要写这个案例啊,不仅为了我们能够理解IOC容器也为了我们后续的文章将AOP和AOP的经典实现事务控制铺垫的。

Coding

  • 首先整体的代码结构很简单,在这里也说明一下

30358f960e995a6895369cc926e5787b.png
  • Bean的配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--跟标签beans,里面配置一个又一个的bean子标签,每一个bean子标签都代表一个类的配置-->
<beans><!--id标识对象,class是类的全限定类名--><bean id="orderDao" class="com.customize.spring.dao.impl.OrderDaoImpl"></bean><bean id="stockDao" class="com.customize.spring.dao.impl.StockDaoImpl"></bean><bean id="orderService" class="com.customize.spring.service.impl.OrderServiceImpl"><!--通过set方法注入--><property name="setOrderDao" ref="orderDao"></property><property name="setStockDao" ref="stockDao"></property></bean>
</beans>
  • 创建Bean对象”工厂“进行创建
  • 主要就是读取xml,通过set方法传值。
public class BeanFactory {/*** 存放对象*/private static Map<String, Object> map = new ConcurrentHashMap<>();/*** 对外提供的接口* @param id* @return*/public static  Object getBean(String id) {return map.get(id);}static {// 只加载一次就是在BeanFactory初始化的时候去加载类// 任务一:读取解析xml,通过反射技术实例化对象并且存储待用(map集合)System.out.println("开始加载Bean对象");// 加载xmlInputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");// 解析xmlSAXReader saxReader = new SAXReader();try {Document document = saxReader.read(resourceAsStream);Element rootElement = document.getRootElement();List<Element> beanList = rootElement.selectNodes("//bean");for (int i = 0; i < beanList.size(); i++) {Element element =  beanList.get(i);// 处理每个bean元素,获取到该元素的id 和 class 属性String id = element.attributeValue("id");String clazz = element.attributeValue("class");// 通过反射技术实例化对象Class<?> aClass = Class.forName(clazz);Object o = aClass.newInstance();// 存储到map中待用map.put(id,o);}// 实例化完成之后维护对象的依赖关系,检查哪些对象需要传值进入,根据它的配置,我们传入相应的值// 有property子元素的bean就有传值需求List<Element> propertyList = rootElement.selectNodes("//property");// 解析property,获取父元素for (int i = 0; i < propertyList.size(); i++) {Element element =  propertyList.get(i);String name = element.attributeValue("name");String ref = element.attributeValue("ref");// 找到当前需要被处理依赖关系的beanElement parent = element.getParent();// 调用父元素对象的反射功能String parentId = parent.attributeValue("id");Object parentObject = map.get(parentId);// 遍历父对象中的所有方法,找到"set" + nameMethod[] methods = parentObject.getClass().getMethods();for (int j = 0; j < methods.length; j++) {Method method = methods[j];// 该方法就是 setAccountDao(AccountDao accountDao)if(method.getName().equalsIgnoreCase(name)) {method.invoke(parentObject,map.get(ref));}}// 把处理之后的parentObject重新放到map中map.put(parentId,parentObject);}System.out.println("加载完毕,Map中的Bean对象个数为:" + map.size());} catch (Exception e) {e.printStackTrace();}}
}
  • 业务代码
public class OrderServiceImpl implements OrderService {private OrderDao orderDao;private StockDao stockDao;public void setOrderDao(OrderDao orderDao) {this.orderDao = orderDao;}public void setStockDao(StockDao stockDao) {this.stockDao = stockDao;}@Overridepublic void order(Order order) {
//        没有IOC容器的情况下
//        OrderDao orderDao = new OrderDaoImpl();
//        // 保存订单
//        orderDao.save(order);
//
//        //扣除库存
//        StockDao stockDao = new StockDaoImpl();
//        stockDao.subStock(order.getName());// 有IOC容器的基础上orderDao.save(order);//扣除库存stockDao.subStock(order.getName());System.out.println("下单成功");}
}
  • 启动

983bc700575f6b252d66c74d5686f6f1.png
  • 测试
    • 地址: http://localhost:9080/order?userId=857&name=ipone
    • 配图:

a296b9461f79c1d83410d3cab9dee18c.png

项目地址

  • 项目地址
  • 有帮忙到你记得点个小星星哦。

总结

  • 本人水平有限有什么不正确的地方,欢迎大家留言区讨论。

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

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

相关文章

余弦信号频谱表达式_信号傅里叶变换系列文章(1):傅里叶级数、傅里叶系数以及傅里叶变换...

傅里叶级数是周期信号的时域表达式&#xff0c;而傅里叶变换是非周期信号或周期信号的频谱&#xff08;频域函数&#xff09;&#xff0c;要想了解它们之间的关系&#xff0c;需要你耐心看完下面内容。学过"信号与系统"等课程的人往往会被许多问题所困惑&#xff0c;…

5s的app显示无法连接服务器,苹果iphone5s手机无法连接App Store问题解决方法汇总...

iphone5s无法连接App Store怎么办&#xff1f;大家在使用iphone5s过程中可能会遇到无法连接app store的问题&#xff0c;那怎么办呢&#xff1f;本文小编就主要给大家讲解一下如何解决iphone5s无法连接App Store的问题。iphone5s无法连接App Store解决方法如下&#xff1a;1)还…

变频器输出功率_100米的深井泵,如何接变频器,怎样控制

深井水泵的控制上&#xff0c;不外是为了保证负载水流的恒定性&#xff0c;一般可以通过恒压闭环方式来完成&#xff0c;如果有储水池的&#xff0c;液位闭环也可以。而深井水泵选用变频器&#xff0c;变频器装地面&#xff0c;你的线路有100米这么长&#xff0c;一般需要考虑加…

云服务器cvm系统,云服务器 cvm 自带系统

云服务器 cvm 自带系统 内容精选换一换如果Linux操作系统云服务器未安装密码重置插件&#xff0c;可以参见本节内容重新设置密码。本节操作重置的是root用户的密码&#xff0c;您可以重置完root密码后登录云服务器后再更换秘钥或重置非root用户的密码。Windows操作系统请参见重…

js距离单位换算_英语中常用的度量衡等单位,与我们用的不一样,这些差异点快收藏...

在日常生活中&#xff0c;我们几乎每天都会用到度量衡等度量单位&#xff0c;比如&#xff1a;去市场买菜&#xff0c;会用到几斤几两&#xff0c;量距离要知道多长&#xff0c;卖房子必须知道房屋的面积等等。度量单位在我们的生活中是非常重要的&#xff0c;可以说已经到了你…

开发缺点_开发移动端手机APP有哪些优缺点?

在当今移动互联网高速发达的现在&#xff0c;如果非要说什么工具最重要&#xff0c;那么一定要数手机APP了。企业可以借助它来进行移动端的营销&#xff0c;提高企业品牌推广力度和盈利&#xff1b;用户也可以借助它解决日常生活衣食住行等各方面的问题&#xff0c;因此备受人们…

用户修改了信息jwt服务器怎么识别,jwt验证登录信息

为什么要告别session&#xff1f;有这样一个场景&#xff0c;系统的数据量达到千万级&#xff0c;需要几台服务器部署&#xff0c;当一个用户在其中一台服务器登录后&#xff0c;用session保存其登录信息&#xff0c;其他服务器怎么知道该用户登录了&#xff1f;(单点登录)&…

获取朋友圈照片_朋友圈可以发 30 秒视频啦!用微视这个新功能就能办到

对于许多热爱分享生活中所见所闻的朋友来说&#xff0c;在发朋友圈时可能都会有这样的感觉&#xff1a;只能分享 15 秒以内的视频&#xff0c;完全不够用啊。如果你也有同样的困扰&#xff0c;今天&#xff0c;A 君就给你介绍一个实用新功能&#xff0c;让你能够在朋友圈中尽情…

苹果手机更改照片大小kb_苹果手机照片视频删除了怎样恢复?专业人士建议你这样做...

照片视频记录我们的点点滴滴&#xff0c;成长中的酸甜苦辣。当我们手机相册中的照片视频误删了我们该怎么做呢&#xff1f;如何才能挽回我们的损失&#xff1f;来看看专家让你怎么做。方法一&#xff1a;【最近删除】苹果自带有一个照片回收站【最近删除】恢复功能可以恢复里面…

复制过去格式不一样_不一样的立春节气:一个新的轮回开启,万物更新,疫情终将过去...

今天是立春&#xff0c;二十四节气中第一个节气&#xff0c;也是一个充满希望的节气。我国自古是农业大国&#xff0c;春种秋收&#xff0c;二十四节气是我国劳动人民独创的&#xff0c;也是先辈们了解自然的智慧结晶。它反映了季节的变化&#xff0c;影响着千家万户的衣食住行…

字符去多余空格_【Excel技巧】批量去空格删换行,用这两个函数简单又快速

今天分享两个函数TRIM函数和CLEAN函数。估计有些人还没见过这两个函数吧&#xff0c;不知道它们是用来干嘛的。跟你说啊&#xff0c;这两个函数都是用来清理、规范数据的。别不信&#xff0c;现在我们一起来看看他们的用法。一、TRIM函数比如&#xff0c;从网页上复制一份数据粘…

逗号后面统一加空格_用99个空格来提取Excel单元格数据,真的是脑洞大开!!!...

回复[目录]学习113篇Excel教程全套Excel视频教程&#xff0c;微信扫码观看需要从规格型号中提取容值、封装、耐压三组数据&#xff0c;如下&#xff1a; 数据源在A列&#xff0c;数据量很大&#xff0c;需要提取的容值、封装和耐压三项数据在单元格中的字节位置不固定。能找到的…

微服务 注册中心_4.微服务架构的第二个组件:注册中心

在微服务架构下&#xff0c;主要有三种角色&#xff1a;服务提供者(RPC Server)服务消费者(RPC Client)服务注册中心(Registry)RPC Server&#xff1a;服务提供者&#xff0c;启动时根据服务发布文件server.xml中的配置信息向Registry注册自身服务&#xff0c;并定期向Registry…

2018怎么打开2019_2019 年,我还是没有摆脱 Micro USB

时间回到 2017 年春&#xff0c;那时候的我想买一块移动硬盘。当时乐视的超级手机已经发布一年多了&#xff0c;苹果也在前一年发布了新款 MacBook Pro&#xff0c;USB Type-C 这个新鲜的接口已经进入大众的视野。移动硬盘常用的 Micro USB 3.0 接口的质量良莠不齐&#xff0c;…

中添加复选框_Word/excel中在方框中打钩/叉的符号,简单方便快捷

方法1&#xff1a;插入特殊符号将光标定位于需要打钩的地方&#xff0c;选择【插入】——【符号】——【其他符号】——更改字体为【Windings2】方法2&#xff1a;使用快捷键从上面的截图中可以看到设置快捷键&#xff0c;所以在插入特殊符号的时候就可以输入数字2611后按住【A…

2 数据源配置_如何在程序运行中动态切换数据源?架构师必读秘笈

说起动态数据源&#xff0c;大家应该也不陌生。例如在读写分离系统中&#xff0c;则要对请求中的读写操作进行分离&#xff0c;让读和写落在不同的数据库上&#xff1b;例如在多租户系统中&#xff0c;则要根据请求来源租户的不同&#xff0c;让其落在不同租户的数据库上&#…

数字滚动_告别单调!让PPT数字滚动起来。

大家好&#xff0c;我是三石。在PPT的制作过程中&#xff0c;数字是不可缺少的元素。如何设计制作&#xff0c;才能使简单的数字变得有活力。废话不多说看效果~其实制作方式很简单&#xff0c;跟着我的步骤你也能做出来。制作步骤&#xff1a;1、首先要制作出数字条可以通过Exc…

mysql字段是否存在_mysql判断列是否存在

本篇文章将通过存储过程来判断列(字段)是否存在。请看详情。推荐课程&#xff1a;MySQL教程。判断字段是否存在&#xff1a;DROP PROCEDURE IF EXISTS schema_change;DELIMITER //CREATE PROCEDURE schema_change() BEGINDECLARE CurrentDatabase VARCHAR(100);SELECT DATABASE…

ubuntu apache2 mysql_折腾 Ubuntu 系统续之安装PHP、Apache2和Mysql

一个狗血的开始接上回的折腾&#xff0c;话说昨天晚上狗屎运来临&#xff0c;在重装了一次的 Ubuntu 系统上&#xff0c;居然顺利的安装了 QQ、PHP7、Apache2、phpMyAdmin、chrome stable、Sublime Text3 并注册成功、git&#xff0c;还有其他桌面美化的东西&#xff0c;如 Doc…

fscanf不读取_思考了一天,终于把matlab的fscanf中的sizeA搞清楚了

数值如12345等可以作为字符&#xff0c;所以以字符格式读取文件时&#xff0c;这些数字照样可以被读取 A fscanf(fileID,formatSpec) A fscanf(fileID,formatSpec,sizeA) 以上是fscanf的语法&#xff1b; sizeA起到的作用是限制&#xff0c;限制读取读取文件中数据的数量&…