日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

抛开 Spring 去理解 IOC 思想:原来 IOC 容器这么简单

發布時間:2025/3/21 javascript 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 抛开 Spring 去理解 IOC 思想:原来 IOC 容器这么简单 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 很多小伙伴們看到標題可能就會想到拋開 Spring 就不會存在 IOC 思想了,其實不然在接下來的文章中就會講述到。
  • 很多小伙伴在理解 IOC 的時候通常會和 Spring 放到一起去學習,首先呢 Spring 設計的非常之巧妙而且里面包含了很多除去 IOC 的其他功能。這樣會導致我們在 Spring 的基礎去理解 IOC 就變得很困難。很難抓住其核心思想。
  • 所以本文的標題的含義就是單純的去理解 IOC 思想,然后通過自定義的 IOC 去加深對 IOC 的理解。
  • 看完本文之后再去理解 Spring 中的 IOC 其實思想是一致的,只是實現上有些出入。畢竟 Spring 是大神們經過深思熟慮后的成果。

傳統的思想(沒有 IOC 容器的情況下)

在沒有 IOC 容器的情況下,如果我們需要某個類具體的操作如下所示:

傳統的 Bean 創建

  • 程序員對 A 進行了主動的使用(new)即創建了 A 類,A 類中又依賴 B 類然后在對 B 類進行創建
  • 創建對象的權利現在是程序員手上需要哪個類就會對那個類進行創建
  • B 類是由于程序員調用了 A 類有對 B 類的依賴隨著而創建
  • 總之就是自己動手豐衣足食,沒有借助任何中間產物。
  • 優點

    • 很直接的一個優點就是簡單,我們需要什么就去創建什么,在程序員的角度上也是比較直觀容易理解的。

    缺點

    • Bean 之間的協調關系是由程序內部代碼來控制的即通過 New 關鍵字與我們的業務代碼進行了強耦合。
    • 沒有對 Bean 進行管理。
    • 對 Bean 沒有進行統一的管理和配置。

    IOC 思想

    首先在這里強調一下 IOC 不是 Spring 提出來了,在 Spring 之前就已經有人提出了 IOC 思想,只不過在 Spring 之前都是偏理論化沒有一個具體的落地方案,Spring 在技術層面把 IOC 思想體現的淋漓盡致。

    什么是 IOC(Inversion of controller)

    • IOC 是一種思想,而不是一個技術的實現。
    • 主要的描述是在軟件開發的領域對象的創建和管理的問題。
    • 上述我們了解了傳統的開發模式,我們再來看看如果有 IOC 的思想下程序員是如何使用對象的。

    從上圖可知:

    • 程序員只需要告訴 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 容器。你可以講出的具體思路嘛? 可以先想一想在繼續往下看,看看是不是和自己的想法不謀而合。
    • 思路大致如下所示:

    • 想必大家都有自己的一定的理解,可能做法比較簡單,但是對于理解 IOC 容器而已其實已經足夠了。如果想更加準確或者深入了解其底層實現,可以按照這個思路去看 Spring 的相關源碼實現,相信你一定會得心應手。

    小案例

    • 我們通過一個小案例來寫我們的 IOC 容器
    • 我們經常購物,我們可以把購物簡單的理解成下單和減庫存兩個操作。
    • 有同學會問為什么要寫這個案例啊,不僅為了我們能夠理解 IOC 容器也為了我們后續的文章將 AOP 和 AOP 的經典實現事務控制鋪墊的。

    Coding

    • 首先整體的代碼結構很簡單,在這里也說明一下

    • 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 方法Method[] methods = parentObject.getClass().getMethods();for (int j = 0; j < methods.length; j++) {Method method = methods[j];// 該方法就是 set 方法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("下單成功");} }
    • 啟動
    • 測試 地址: http://localhost:9080/order?userId=857&name=ipone
      配圖:

    作者:后端學長
    鏈接:https://juejin.im/post/5eb022e7f265da7bb46bcd9d

    總結

    以上是生活随笔為你收集整理的抛开 Spring 去理解 IOC 思想:原来 IOC 容器这么简单的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。