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

歡迎訪問 生活随笔!

生活随笔

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

javascript

Spring IoC?看这篇文章就够了...

發布時間:2025/3/11 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring IoC?看这篇文章就够了... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

剛開始聽到 IoC,會覺得特別高大上,但其實明白原理了很簡單。

跟著我的腳步,一文帶你吃透 IoC 原理。

本文圍繞 是何、為何、如何 來談:

是何

上一篇文章有同學問我在官網該看哪些內容,怎么找的,那今天的截圖里都會有鏈接。

初識 IoC

根據上一篇文章我們說的,Spring 全家桶中最重要的幾個項目都是基于 Spring Framework 的,所以我們就以 Spring Framework 為例來看文檔[2]

首先它的右側有 Github 的鏈接,另外點到「LEARN」這里,就會看到各個版本的文檔。

那我們點「Reference Doc」,就能夠看到它的一些模塊的介紹:

(等下... 模塊?什么是模塊?這個問題下文回答。)

第一章 Overview,講述它的歷史、設計原理等等;

第二章 Core,包含了 IoC 容器,AOP 等等,那自然是講 Spring 的核心了,要點進去好好看了。

點進去之后發現了寶貴的學習資料,一切的 what, why, how 都可以在這里找到答案。

這里很好的解釋了大名鼎鼎的 IoC - Inversion of Control, 控制反轉。

我粗略的總結一下:控制反轉就是把創建和管理 bean 的過程轉移給了第三方。而這個第三方,就是 Spring IoC Container,對于 IoC 來說,最重要的就是容器

容器負責創建、配置和管理 bean,也就是它管理著 bean 的生命,控制著 bean 的依賴注入。

通俗點講,因為項目中每次創建對象是很麻煩的,所以我們使用 Spring IoC 容器來管理這些對象,需要的時候你就直接用,不用管它是怎么來的、什么時候要銷毀,只管用就好了。

舉個例子,就好像父母沒時間管孩子,就把小朋友交給托管所,就安心的去上班而不用管孩子了。托兒所,就是第三方容器,負責管理小朋友的吃喝玩樂;父母,相當于程序員,只管接送孩子,不用管他們吃喝。

等下,bean?又是什么?

Bean 其實就是包裝了的 Object,無論是控制反轉還是依賴注入,它們的主語都是 object,而 bean 就是由第三方包裝好了的 object。(想一下別人送禮物給你的時候都是要包裝一下的,自己造的就免了。

Bean 是 Spring 的主角,有種說法叫 Spring 就是面向 bean 的編程(Bean Oriented Programming, BOP)。

IoC 容器

既然說容器是 IoC 最重要的部分,那么 Spring 如何設計容器的呢?還是回到官網,第二段有介紹哦:

答:使用?ApplicationContext,它是?BeanFactory?的子類,更好的補充并實現了?BeanFactory?的。

BeanFactory?簡單粗暴,可以理解為 HashMap:

  • Key - bean name

  • Value - bean object

但它一般只有 get, put 兩個功能,所以稱之為“低級容器”。

而?ApplicationContext?多了很多功能,因為它繼承了多個接口,可稱之為“高級容器”。在下文的搭建項目中,我們會使用它。

ApplicationContext?的里面有兩個具體的實現子類,用來讀取配置配件的:

  • ClassPathXmlApplicationContext?- 從 class path 中加載配置文件,更常用一些;

  • FileSystemXmlApplicationContext?- 從本地文件中加載配置文件,不是很常用,如果再到 Linux 環境中,還要改路徑,不是很方便。

當我們點開?ClassPathXmlApplicationContext?時,發現它并不是直接繼承?ApplicationContext?的,它有很多層的依賴關系,每層的子類都是對父類的補充實現。

而再往上找,發現最上層的 class 回到了?BeanFactory,所以它非常重要。

要注意,Spring 中還有個?FactoryBean,兩者并沒有特別的關系,只是名字比較接近,所以不要弄混了順序。

為了好理解 IoC,我們先來回顧一下不用 IoC 時寫代碼的過程。

深入理解 IoC

這里用經典?class Rectangle?來舉例:

  • 兩個變量:長和寬

  • 自動生成?set()?方法和?toString()?方法

注意 ??:一定要生成?set()?方法,因為 Spring IoC 就是通過這個?set()?方法注入的;toString()?方法是為了我們方便打印查看。

public?class?Rectangle?{private?int?width;private?int?length;public?Rectangle()?{System.out.println("Hello?World!");}public?void?setWidth(int?widTth)?{this.width?=?widTth;}public?void?setLength(int?length)?{this.length?=?length;}@Overridepublic?String?toString()?{return?"Rectangle{"?+"width="?+?width?+",?length="?+?length?+'}';} }

然后在?test?文件中手動用?set()?方法給變量賦值。

嗯,其實這個就是「解藕」的過程!

public?class?MyTest?{@Testpublic?void?myTest()?{Rectangle?rect?=?new?Rectangle();rect.setLength(2);rect.setWidth(3);System.out.println(rect);} }

其實這就是 IoC 給屬性賦值的實現方法,我們把「創建對象的過程」轉移給了?set()?方法,而不是靠自己去?new,就不是自己創建的了。

這里我所說的“自己創建”,指的是直接在對象內部來?new,是程序主動創建對象的正向的過程;這里使用?set()?方法,是別人(test)給我的;而 IoC 是用它的容器來創建、管理這些對象的,其實也是用的這個?set()?方法,不信,你把這個這個方法去掉或者改個名字試試?

幾個關鍵問題:

何為控制,控制的是什么?

答:是 bean 的創建、管理的權利,控制 bean 的整個生命周期。

何為反轉,反轉了什么?

答:把這個權利交給了 Spring 容器,而不是自己去控制,就是反轉。由之前的自己主動創建對象,變成現在被動接收別人給我們的對象的過程,這就是反轉。

舉個生活中的例子,主動投資和被動投資。

自己炒股、選股票的人就是主動投資,主動權掌握在自己的手中;而買基金的人就是被動投資,把主動權交給了基金經理,除非你把這個基金賣了,否則具體選哪些投資產品都是基金經理決定的。

依賴注入

回到文檔中,第二句話它說:IoC is also known as DI.

我們來談談?dependency injection?- 依賴注入。

何為依賴,依賴什么?

程序運行需要依賴外部的資源,提供程序內對象的所需要的數據、資源。

何為注入,注入什么?

配置文件把資源從外部注入到內部,容器加載了外部的文件、對象、數據,然后把這些資源注入給程序內的對象,維護了程序內外對象之間的依賴關系。

所以說,控制反轉是通過依賴注入實現的。但是你品,你細品,它們是有差別的,像是「從不同角度描述的同一件事」:

  • IoC 是設計思想,DI 是具體的實現方式;

  • IoC 是理論,DI 是實踐;

從而實現對象之間的解藕。

當然,IoC 也可以通過其他的方式來實現,而 DI 只是 Spring 的選擇。

IoC 和 DI 也并非 Spring 框架提出來的,Spring 只是應用了這個設計思想和理念到自己的框架里去。

為何

那么為什么要用 IoC 這種思想呢?換句話說,IoC 能給我們帶來什么好處?

答:解藕。

它把對象之間的依賴關系轉成用配置文件來管理,由 Spring IoC Container 來管理。

在項目中,底層的實現都是由很多個對象組成的,對象之間彼此合作實現項目的業務邏輯。但是,很多很多對象緊密結合在一起,一旦有一方出問題了,必然會對其他對象有所影響,所以才有了解藕的這種設計思想。

如上圖所示,本來 ABCD 是互相關聯在一起的,當加入第三方容器的管理之后,每個對象都和第三方法的 IoC 容器關聯,彼此之間不再直接聯系在一起了,沒有了耦合關系,全部對象都交由容器來控制,降低了這些對象的親密度,就叫“解藕”。

如何

最后到了實踐部分,我們來真的搭建一個 Spring 項目,使用下 IoC 感受一下。

現在大都使用?maven?來構建項目,方便我們管理 jar 包;但我這里先講一下手動導入 jar 包的過程,中間會遇到很多問題,都是很好的學習機會。

在開始之前,我們先來看下圖 - 大名鼎鼎的 Spring 模塊圖。

Spring Framework 八大模塊

模塊化的思想是 Spring 中非常重要的思想。

Spring 框架是一個分層架構,每個模塊既可以單獨使用,又可與其他模塊聯合使用。

每個「綠框」,對應一個模塊,總共8個模塊;「黑色包」,表示要實現這個模塊的 jar 包。

Core Container,我們剛才已經在文檔里看到過了,就是 IoC 容器,是核心,可以看到它依賴于這4個 jar 包:

  • Beans

  • Core

  • Context

  • SpEL, spring express language

那這里我們就知道了,如果想要用 IoC 這個功能,需要把這 4個 jar 包導進去。其中,Core 模塊是 Spring 的核心,Spring 的所有功能都依賴于這個 jar 包,Core 主要是實現 IoC 功能,那么說白了 Spring 的所有功能都是借助于 IoC 實現的。

其他的模塊和本文關系不大,不在這里展開了。

那當我們想搭建 Spring 項目時,當然可以把所有 jar 包都導進去,但是你的電腦能受得了嗎。。?但是包越大,項目越大,問題就越多,所以盡量按需選擇,不用囤貨。。

Btw, 這張圖在網上有很多,但是在我卻沒有在最新版的 reference doc 上找到。。不過,既然那些老的教程里有,說明老版本的 doc 里有,那去老版本的介紹[3]?里找找看????

在本文第一張圖?Spring Framework?-?Documentation?中我們選?4.3.26?的?Reference Doc.,然后搜索“Framework Modules”,就有啦~ 具體鏈接可以看文末參考資料。

還有一個方法,待會我們講到 jar 包中的內容時再說。

搭建 Spring 項目

知道要導入哪些 jar 包了,那就找吧????。

一、手動加載 jar 包的方式

1. 下載

下載地址:

如果你要問我怎么找的,那就還是從剛才?4.3.26?版本的?Reference Doc?中進去,然后剛開頭就有一個?Distribution Zip Files,

好奇心帶著我打開了它,發現...

發現了倉庫地址!

打開后發現是各個版本的 jar 包啊~

我們搜 5.2.3 版的,它在最下面:

然后就可以愉快的使用了~

  • Dist.zip?是 jar 包

  • Docs.zip?是文檔

其他的暫時先不用管~

下載好了之后,就好好看看 Spring 送我們的這份大禮包吧。

此處回答上文的遺留問題:哪里找 Spring Framework 框架圖。

答案是:下載的 docs.zip → spring-framework-reference → images → spring-overview

我們需要導入 Intellij 的 jar 包在哪里呢?Dist.zip → libs

這里可以看到,每個黑色框對應3個 jar 包,我們要導入 Intellij 的是?RELEASE.jar.

2. 不用 IoC 構建項目

我們?new project,不用 maven 構架,就新建一個普通的 Java 項目,比如我就叫它?Spring_HelloWorld,然后還是用我常用的?class Rectangle?的例子。

然后在 External Libraries 中導入我們剛才在模塊圖里看到的那4個模塊所對應的 jar 包,結構如下:

這樣你以為就大功告成了嗎?Too young too simple 啊~

來運行一下:

出現了老盆友:no class def found?error, 就是找不到這個類。

我們谷歌?Maven common logging?并下載它的 jar 包,再加到項目里就可以了。

我上圖里是已經加過了的,所以你會看到一個?commons-logging-1.2.

再運行一下就可以了。這里的兩個文件上文都有截圖。

目前為止我們是手動用?set()?方法設置對象的,那怎么用 Spring IoC 呢?

3. Spring IoC 配置文件詳解

還需要有一個配置文件,可是這個文件需要配置啥,該怎么配置呢?

官網里都給我們寫好了:

第一段是一些命名空間及其規范的介紹,

第二段就是給?bean?的屬性賦值了。

這里注意下?bean?里面的配置要改一下,改成我們這個項目對應的。這里的?id,?class?是什么意思呢?官網上也有解釋,我這里簡單概括下:

  • bean?標簽:告訴 Spring 要創建的對象

  • id: 對象的唯一標識,就像每個人的身份證一樣,不可重復

  • class:?bean?的完全限定名,即從 package name 到 class name

  • property:給屬性賦值,name?的名稱取決于?set()?方法后面的參數;

其實也可以用 constructor 來賦值,name 的名稱取決于參數列表;更多給復雜數據類型賦值的使用可以在官網查到。

當然,在工作中更常用的是注解。但是往往也會有 xml 文件配合著一起使用的,所以還是要懂的。

我的 service 文件配置如下:

4. 最后一步,我們再來看它是怎么用的:

這里面并沒有直接的 new 這個 service,但是 Spring 容器幫我們創建了這個對象。

那么 Spring 是如何幫我們創建對象的呢?

ApplicationContext?是?IoC 容器的入口,其實也就是?Spring 程序的入口, 剛才已經說過了它的兩個具體的實現子類,在這里用了從 class path 中讀取數據的方式;

然后第二行,就是獲取具體的 bean 了。這個其實有很多方式,在使用的時候就能看到:

點進去發現,是在 BeanFactory.class 里定義的:

這其中比較常用的是通過

  • Id ?→ 需要 cast

  • Bean 的類型 → 只能在 Singleton 的時候使用,否則不知道用哪個呀

  • Id + 類型 → 下圖代碼示例

來獲取對象,最后兩種 String, Class objects 這種可變參數的方式用的很少。

照貓畫虎,我的 test 文件改動如下:

成功運行~~????????

Follow up 1. 對象在容器中默認是單例的

實踐是檢驗的唯一標準:

再用?getBean()?得到一個對象,測試是否還是同一個。

即:

public?class?MyTest?{public?void?test?myTest()?{ApplicationContext?context?=?new?ClassPathXmlApplicationContext("service.xml");Rectangle?rect?=?context.getBean("rectangle",?Rectangle.class);Rectangle?rect2?=?context.getBean("rectangle",?Rectangle.class);System.out.println(rect?==?rect2);}} }

返回 True or False?

答:True

因為默認是單例的,如果要改,需要在配置文件里改<bean … scope = “prototype”>.

至于這些標簽的用法,這里不再延伸了~

Follow up 2. 容器中的對象是什么時候創建的?

實踐是檢驗的唯一標準:

定義一個無參的 constructor,里面打印一句話,然后只?new ClassPathXmlApplicationContext,如下圖:

發現也是可以打印的,所以其實是每次啟動容器的時候,就已經創建好容器中的所有對象了。(當然,這在?scope = "prototype"?的時候不適用,只是 singleton 的時候。)

多說一句,其實最好應該一直保留一個無參的 constructor,因為這里 bean 對象的創建是通過反射,

  • clazz.newInstance()?默認是調用無參的 constructor

不過,現在已經被棄用掉了,換用了這個:

  • clazz.getDeclaredConstructor().newInstance()

二、使用 Maven 構建項目

我們再回到最開始的構建項目,相信大家都體會到了手動導入 jar 包的繁瑣之處,其實我們還可以用 Maven 來管理項目中的 jar 包,在公司中也是比較常用的一種方式,免除了手動下載 jar 包的過程。

1. 新建項目

使用 Maven 的話就簡化很多了,首先我們創建一個 Maven 項目,不同于剛才的過程在于:

New Project 的時候要選擇從 Maven 構建,而不是一個簡單的 Java 項目。

建好之后,我們會發現比起剛才的 Java 項目,多了很多東西:

和之前的空項目不太一樣,這里有?main,?test,其中?resources?是放配置文件的地方,也就是我們剛才的?service.xml?應該放在這里,如果沒有放對位置是代碼找不到哦~

2. 添加對應的 pom 依賴,就不用手動導 jar 包了

  • 倉庫地址?https://mvnrepository.com/

  • 搜?spring

  • 選擇?Spring context?→?5.2.3 release,把里面的配置 copy 到?pom.xml?中

  • 最終在左邊 external libraries 會自動出現所需的包,一鍵導入,不要太方便~

    3. 寫代碼~~????????

    小結

    我們最后再來體會一下用 Spring 創建對象的過程:

    通過?ApplicationContext?這個 IoC 容器的入口,用它的兩個具體的實現子類,從 class path 或者 file path 中讀取數據,用?getBean()?獲取具體的 bean instance。

    那使用 Spring 到底省略了我們什么工作?

    答:new 的過程。把 new 的過程交給第三方來創建、管理,這就是「解藕」。

    Spring 也是用的?set()?方法,它只不過提供了一套更加完善的實現機制而已。

    而說到底,底層的原理并沒有很復雜,只是為了提高擴展性、兼容性,Spring 提供了豐富的支持,所以才覺得源碼比較難。

    因為框架是要給各種各樣的用戶來使用的,它們考慮的更多的是擴展性。如果讓我們來實現,或許三五行就能搞定,但是我們實現的不完善、不完整、不嚴謹,總之不高大上,所以它寫三五十行,把框架設計的盡可能的完善,提供了豐富的支持,滿足不同用戶的需求,才能占領更大的市場啊。

    參考資料

    [1]

    我的 Github:?https://github.com/huiqit/SheIsSDEatNYC

    [2]

    Spring 官方文檔:?https://spring.io/projects/spring-framework#learn.

    [3]

    官方文檔 4.3.26 版本,包含 Spring 模塊圖:?https://docs.spring.io/spring/docs/4.3.26.RELEASE/spring-framework-reference/htmlsingle/

    部分圖片來源于網絡,版權歸原作者,侵刪。

    END

    史上最全的延遲任務實現方式匯總!附代碼(強烈推薦)

    想讀Spring源碼?先從這篇「 極簡教程」開始

    99%的程序員都在用Lombok,原理竟然這么簡單?我也手擼了一個!|建議收藏!!!

    關注公眾號發送”進群“,老王拉你進讀者群。

    總結

    以上是生活随笔為你收集整理的Spring IoC?看这篇文章就够了...的全部內容,希望文章能夠幫你解決所遇到的問題。

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