Spring框架概述及核心設(shè)計思想分享
一. Spring框架概述
1. 什么是Spring框架
我們通常所說的 Spring 指的是 Spring Framework(Spring 框架),它是?個開源框架,有著活躍而龐大的社區(qū),這就是它之所以能長久不衰的原因;Spring 支持廣泛的應(yīng)用場景,它可以讓 Java 企業(yè)級的應(yīng)用程序開發(fā)起來更簡單。
用?句話概括 Spring:Spring 框架是包含了眾多工具方法的 IoC 容器。
2. 為什么要學(xué)習框架?
因為學(xué)習框架相當于從“小作坊”到“工廠”的升級,小作坊什么都要自己做,工廠是組件式裝配,特點就是高效。
框架更加易?、簡單且高效。
Servlet有以下痛點:
- 添加外部 jar 不?便,容易出錯,比如添加了?個不匹配的外部 jar 版本。
- 運行和調(diào)試的時候需要配置 Tomcat 不?便。
- 發(fā)布不方便,Servlet 項目必須依靠外置的 Tomcat(外置的 Web 容器)運行。
- 路由配置不方便,?個訪問地址對應(yīng)?個 Servlet 類。
- …
而 Spring Boot 相比于 Servlet 具備以下優(yōu)點:
- 快速添加外部 jar 包。
- 調(diào)試項目更方便,無需配置 Tomcat,點擊“運行”按鈕就可以直接運行項目,因為 Spring Boot 內(nèi)置了 Tomcat 容器可直接運行,但是 Servlet 需外掛 Tomcat。
- 發(fā)布項目更加方便,無需配置 Tomcat,使用 java -jar 方式就可以發(fā)布。
- 對象自動裝配。
- 添加路由更加方便,無需每個訪問地址都添加?個類。
- …
3. Spring框架學(xué)習的難點
- 配置比較多。
- 需要?量的外部 jar 包,在下載時容易出錯。
- 會涉及簡單的軟件?程的設(shè)計思想(分層思想:前后端的分層思想;后端工程的分層思想)。
- 知識點相對來說比之前的知識更加的分散,要仔細聽才能搞懂各個知識點的邏輯關(guān)系。
- 要記的東西很多,所以要大量地重復(fù)練習才能記住,比如各種注解。
Spring框架基本學(xué)習應(yīng)用路線:Spring全家桶(Spring/Spring Boot/Spring MVC) -> MyBatis -> Redis 等。
二. Spring核心設(shè)計思想
Spring 核心就是這么一句話:Spring 框架是包含了眾多工具方法的 IoC 容器。
那么這句話怎么理解呢?什么是容器?什么又是 IoC?
1. 容器是什么?
容器是用來容納某種物品的(基本)裝置。 ——來?:百度百科
Java 中也有一些容器,比如 List,Map,Set 等這些集合,是屬于數(shù)據(jù)儲存的容器,它把我們常用的操作都封裝到集合中了,我們只需要知道集合為我們提供的方法就可以使用各種集合了;還有 Tomcat 是屬于 Web 容器,同理 Spring 是就一個 IoC 容器,它包含了許多的工具和方法。
2. IoC是什么?
IoC 即 Inversion of Control
,直譯過來就是控制反轉(zhuǎn)的意思,這是一種思想,控制權(quán)反轉(zhuǎn),在 Java 的常規(guī)代碼中,對象的生命周期,是由當前代碼(程序員自己)控制的,而控制權(quán)反轉(zhuǎn)就是對象的生命周期,不再由當前代碼片段來控制,而是由 Spring(IoC 容器)來控制 。
這種思想還比較抽象,我們來通過一個例子來了解它。
我們都知道汽車,它包含輪胎,底座,車身等,現(xiàn)在我們要造一輛汽車時,需要有車身,而車身需要有底座和輪胎,最傳統(tǒng)的思想就是造車時,需要車身,于是就new
一個車身,而車身需要底座,于是就再new
一個底座,同理底座需要輪胎,那就造底座前new
一個輪胎。
我們可以得到以下代碼:
package old; /** * 傳統(tǒng)開發(fā)方式, 耦合性問題 */ // 汽車類 public class Car { // 車身 private Framework framework; public Car() { framework = new Framework(); } public void init() { System.out.println("do car"); // 汽車的組建依賴于車身 framework.init(); } } package old; // 車身類 public class Framework { private Bottom bottom; public Framework() { bottom = new Bottom(); } public void init() { System.out.println("do framework"); // 車身的組建依賴于底盤 bottom.init(); } } package old; // 底盤類 public class Bottom { private Tire tire; public Bottom() { tire = new Tire(); } public void init() { System.out.println("do bottom"); // 底盤的組建依賴于輪胎 tire.init(); } } package old; // 輪胎類 public class Tire { private int size = 17; // 輪胎的尺寸 public void init() { System.out.println("size -> " + size); } } package old; public class Test { public static void main(String[] args) { Car car = new Car(); car.init(); } }
但是,但上面的代碼中,輪胎的大小是固定寫死的, 然而隨著對的車的需求量越來越大,個性化需求也會越來越多,這 時候我們就需要加?多種尺寸的輪胎,那這個時候就要對上面的程序進行修改了,根據(jù)我們上面寫的代碼,我們需要往輪胎Tire
類的構(gòu)造方法加上一個參數(shù),由于底盤Bottom
類控制著Tire
類,那么底盤類的構(gòu)造方法也需要加上一個參數(shù),以此類推,我們的車身Framework
類與汽車Car
類都需要為構(gòu)造方法加上參數(shù),于是我們得到了如下的代碼:
package old; /** * 傳統(tǒng)開發(fā)方式, 耦合性問題 */ // 汽車類 public class Car { // 車身 private Framework framework; public Car(int size) { framework = new Framework(size); } public void init() { System.out.println("do car"); // 汽車的組建依賴于車身 framework.init(); } } package old; // 車身類 public class Framework { private Bottom bottom; public Framework(int size) { bottom = new Bottom(size); } public void init() { System.out.println("do framework"); // 車身的組建依賴于底盤 bottom.init(); } } package old; // 底盤類 public class Bottom { private Tire tire; public Bottom(int size) { tire = new Tire(size); } public void init() { System.out.println("do bottom"); // 底盤的組建依賴于輪胎 tire.init(); } } package old; // 輪胎類 public class Tire { private int size = 17; // 輪胎的尺寸 public Tire(int size) { this.size = size; } public void init() { System.out.println("size -> " + size); } } package old; public class Test { public static void main(String[] args) { Car car = new Car(20); car.init(); } }
此時,如果需要個性化定制輪胎的大小,就可以只改動構(gòu)造Car
對象傳入的參數(shù)就可以了;但是,如果再加上加上一個需求,還要定制輪胎的顏色,那我們又要加參數(shù),此時就意味著像上面一樣修改最底層的代碼, 整個調(diào)?鏈上的所有代碼都需要修改。
這樣的代碼耦合性就太高了,為了解決這個問題,我們可以使用loC
的思想來實現(xiàn)代碼,將控制權(quán)交出去,也就是說,IoC
模式下,我們不再自己構(gòu)造創(chuàng)建對象,當我們需要輪胎Tire
類時,你就給我傳一個Tire
對象,我們不去new
一個Tire
對象了,這樣的話,就算在Tire
類加參數(shù)也只需要改動Tire
類的構(gòu)造方法與相關(guān)執(zhí)行方法與屬性,頂多再改一下Tire
對象的創(chuàng)建,同理其他類也一樣,將對象作為參數(shù)傳入到上級類的構(gòu)造方法中去就行了,但此時其他類是不需要修改的,這個過程也叫做傳入或注入。
由于我們創(chuàng)建Car
時需要Framework
,所以先要實例一個Framework
對象,同理實例一個Framework
對象需要Bottom
對象,那么需先實例一個Bottom
對象,一樣,在實例Bottom
對象之前需要實例一個Tire
對象,于是需要先后創(chuàng)建Tire
對象,Bottom
對象,Framework
對象后才能創(chuàng)建一個Car
對象,我們可以得到如下的代碼:
package ioc; public class Car { // 汽車的組建依賴于車身的組建 private Framework franmework; public Car(Framework franmework) { this.franmework = franmework; } public void init() { System.out.println("do car..."); franmework.init(); } } package ioc; public class Framework { // 車身的組建依賴于底盤 private Bottom bottom; public Framework(Bottom bottom) { this.bottom = bottom; } public void init() { System.out.println("do franmework"); bottom.init(); } } package ioc; public class Bottom { // 底盤的組建依賴于輪胎 private Tire tire; public Bottom(Tire tire) { this.tire = tire; } public void init() { System.out.println("do bottom..."); tire.init(); } } package ioc; public class Tire { private int size = 17; private String color = "黑色"; public Tire(int size, String color) { this.size = size; this.color = color; } public void init() { System.out.println("size -> " + size); System.out.println("color->" + color); } } package ioc; public class IOCDemo { // 這里的內(nèi)容包含就相當于是 IoC 容器做的事情 // 對象的生命周期控制權(quán)就翻轉(zhuǎn)給 IoC 容器了, 不再由程序員控制 private Tire tire; private Bottom bottom; private Framework framework; public Car car; public IOCDemo() { tire = new Tire(17, "紅色"); bottom = new Bottom(tire); framework = new Framework(bottom); car = new Car(framework); } } package ioc; /** * 模擬 IoC 容器 */ public class Test { public static void main(String[] args) { // 直接使用, 創(chuàng)建就交給IoC了 IOCDemo ioc = new IOCDemo(); Car car = ioc.car; car.init(); } }
此時如果要變需求,需要加參數(shù)或減少參數(shù),IoC 的代碼只需改動圖中的兩處代碼即可, 整個調(diào)用鏈是不用做任何改變的, 達到了解耦的目的。
- 在傳統(tǒng)的代碼中對象創(chuàng)建順序是:Car -> Framework -> Bottom -> Tire
- 改進之后解耦的代碼的對象創(chuàng)建順序是:Tire -> Bottom -> Framework -> Car
到這里我們就可以發(fā)現(xiàn),傳統(tǒng)的代碼類創(chuàng)建順序是反著的,Car 控制 FrameWork,F(xiàn)rameWork 控制著 Bottom,Bottom 控制著 Tire;而改進之后的控制權(quán)發(fā)生了反轉(zhuǎn),是下層將對象注入到當前對象當中,下級的控制權(quán)不再由上級控制了,下級在發(fā)生改變時會將改變完成后的對象注入上級,這樣上級就是不受影響的,這就是 IoC 的實現(xiàn)思想。
所以 IoC 有以下的優(yōu)點:對象(Bean)的生命周期交給 IoC 框架維護,作為程序員無需關(guān)注,說白了就是程序員不需要關(guān)注對象創(chuàng)建、銷毀時機以及對象的依賴關(guān)系,這些工作加個 IoC 框架(也就是 Spring)做就行,實現(xiàn)了代碼的解耦,對象的使用更加方便高效。
3. Spring是IoC容器
Spring 框架就是包含了多個工具方法的 IoC 容器,既然是容器,那它就有存和取的功能,這也是 Spring 最核心的兩個功能:
- 將 Bean(對象)存儲到 Spring 容器中。
- 將 Bean(對象)從 Spring 容器中取出來。
將對象存放到容器有什么好處呢?
將對象存儲到 IoC 容器相當于我們將所有可能用到的工具制作好都放到倉庫,當我們需要使用時直接取即可,用完歸還倉庫;而 new 對象的方式相當于我們每次需要用工具的時候現(xiàn)場制作,制作完了扔掉,下次需要的時候重新做。
Spring 是?個 IoC 容器,說的是對象的創(chuàng)建和銷毀的權(quán)利都交給 Spring 來管理了,它本身?具備了存儲對象和獲取對象的能力。
4. DI(依賴注入)
DI,即Dependency Injection
,依賴注入。
所謂依賴注?,就是由 IoC 容器在運行期間,動態(tài)地將某種依賴關(guān)系注入到對象之中,在pom.xml
有一個依賴項,就是用來導(dǎo)入外部的資源,而這里的依賴注入,導(dǎo)入的不是外部的資源,而是對象;當某個 Java 實例需要另一個 Java 實例時,創(chuàng)建被調(diào)用者的工作不是由調(diào)用者實現(xiàn),而是由 Spring 容器來完成,然后注入調(diào)用者,因此稱為依賴注入。
IoC 與 DI 的區(qū)別是什么?
依賴注入(DI)和控制反轉(zhuǎn)(IoC)是從不同的角度的描述的同?件事情,就是指通過引入 IoC 容器,利用依賴關(guān)系注入的方式,實現(xiàn)對象之間的解耦。
IoC 是“目標”也是?種思想,而目標和思想只是?種指導(dǎo)原則,最終還是要有可行的落地方案,而 DI 就屬于具體的實現(xiàn);也就是說,IoC 是一種思想,而 DI 是 IoC 的一種實現(xiàn)。
5. DL(依賴查找)
DL,即Dependency Lookup
,依賴查找,也是 IoC的一種實現(xiàn)。
依賴查找和依賴注入的區(qū)別在于,依賴注入是將依賴關(guān)系委托給容器,由容器來管理對象之間的依賴關(guān)系,容器外部是不關(guān)心這種依賴關(guān)系的,需要時由容器判斷提供什么;而依賴查找是由對象自己來查找它所依賴的對象,容器只負責管理對象的生命周期,也就是說此時需要容器外部自己確定要容器提供哪種依賴關(guān)系;兩者之間是主動和被動的區(qū)別。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java設(shè)計模塊系列之書店管理系統(tǒng)單機版(一)
這篇文章主要為大家詳細介紹了Java單機版的書店管理系統(tǒng)設(shè)計模塊和思想第一章,感興趣的小伙伴們可以參考一下2016-08-08深入了解SpringBoot中@InitBinder注解的使用
這篇文章主要介紹了深入了解SpringBoot中@InitBinder注解的使用,@InitBinder注解可以作用在被@Controller注解的類的方法上,表示為當前控制器注冊一個屬性編輯器,用于對WebDataBinder進行初始化,且只對當前的Controller有效,需要的朋友可以參考下2023-10-10SpringBoot整合EasyCaptcha實現(xiàn)圖形驗證碼功能
這篇文章主要介紹了SpringBoot整合EasyCaptcha實現(xiàn)圖形驗證碼功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2024-02-02MybatisPlus自動填充創(chuàng)建(更新)時間問題
在開發(fā)數(shù)據(jù)庫相關(guān)應(yīng)用時,手動設(shè)置創(chuàng)建和更新時間會導(dǎo)致代碼冗余,MybatisPlus提供了自動填充功能,通過實現(xiàn)MetaObjectHandler接口并重寫insertFill、updateFill方法,可以自動維護創(chuàng)建時間、更新時間等字段,極大簡化了代碼,這不僅提高了開發(fā)效率,也保證了數(shù)據(jù)的可追溯性2024-09-09