javascript
底层原理_Spring框架底层原理IoC
一、概述
Spring是一個輕量級的開源JavaEE框架
Spring可以解決企業應用開發的復雜性
Spring兩大核心部分:IoC和AOP
特點:
方便解耦,簡化開發
AOP編程支持
方便程序測試
方便和其他框架整合
方便事務操作
降低API開發難度
IoC和AOP是Spring的核心,咱們就從這兩個倆分析其原理,入門案例這里就不寫了,直接進入主題,先來講述IoC,下篇文章將講述AOP
二、IoC解耦推導
我們都知道,IoC是控制反轉,通俗講就是把對象創建和對象之間的調用交給Spring管理,通過簡單的xml配置就可以創建和調用對象,其主要目的就是解耦,降低代碼之間的耦合度,咱們就從傳統方式到IoC來一步一步講述怎樣把耦合度降到最低。
所謂解耦就是降低類之間的依賴和方法之間的依賴
1. 傳統直接調用對象
在我們傳統的開發方式中,是直接采取new對象的方式創建對象,經常可以看到service調用dao這樣的代碼,如果是直接調用,我們來看看是怎么樣子的,創建UserService和UserDao ,通過UserService調用UserDao:
// UserDao1類public class UserDao1 { ? ?public void say(){ ? ? ? ?System.out.println("I am userDao1"); ? }}// UserService類,調用UserDao1類中的方法public class UserService { ? ?public void getUser(UserDao1 userDao1){ ? ? ? ?userDao1.say(); ? }}在上面的代碼中,是最傳統的調用方式,通過service調用dao,可以得到我們想要的結果,打印出:“I am userDao1”,但是,突然,產品經理想要UserDao2一個新的類也可以在UserService中進行調用,這個時候,就需要將代碼改為如下:
// UserDao1類public class UserDao1 { ? ?public void say(){ ? ? ? ?System.out.println("I am userDao1"); ? }}// UserDao2類public class UserDao2 { ? ?public void say(){ ? ? ? ?System.out.println("I am userDao2"); ? }}// UserService類,調用UserDao1和UserDao2類中的方法public class UserService { ? ?public void getUser(UserDao1 userDao1){ ? ? ? ?userDao1.say(); ? } ? ? ? ?public void getUser(UserDao2 userDao2){ ? ? ? ?userDao2.say(); ? }}可以看到,我們不僅要新建一個UserDao2類,還需要修改UserService中的代碼,萬一,突然,產品經理想把UserDao3、UserDao4、UserDao5.....這樣具有相同功能的類也在userService中作為參數進行調用,新建這些類倒還好,避免不了,問題是還要修改UserService類,簡直頭大....
其實,上面的代碼中,UserService就和要調用的dao類具有一種很強的聯系,我們把這種聯系稱為強耦合關系,這種強耦合關系是不利于開發的,因此我們需要解耦,首先想到的便是使用接口進行解耦,也就是面向接口編程。
2. 接口解耦
將上面的代碼進行修改,將UserDao定義為接口,然后去實現這個接口,再進行調用,如下:
// UserDao接口public interface UserDao { ? ?void say();}// 接口實現類UserDao1public class UserDaoImpl1 implements UserDao { ? ?@Override ? ?public void say() { ? ? ? ?System.out.println("I am userDao1"); ? }}// 接口實現類UserDao2public class UserDaoImpl2 implements UserDao { ? ?@Override ? ?public void say() { ? ? ? ?System.out.println("I am userDao2"); ? }}// UserService中進行調用public class UserService { ? ?public void getUser(UserDao userDao){ ? ? ? ?userDao.say(); ? }}在上面的代碼中,我們可以看到,UserService類中getUser方法參數可以是UserDao1類型的,也可以是UserDao2類型的,不像之前的代碼,只能是指定的UserDao。這時,UserService和UserDao1、UserDao2聯系的就沒那么緊密了,這是一種弱耦合關系,通過接口來進行解耦。
但是仔細查看上面的代碼,你會發現,接口和實現類之間還是存在強耦合關系,在面向接口編程中,我們常常會看到類似這樣的代碼:
UserDao userDao = new UserDaoImpl1();假設現在不用這個UserDaoImpl1了,而改用UserDao的另一個實現類UserDaoImpl2,代碼就要改為如下:
UserDao userDao = new UserDaoImpl2();這樣也就是接口和實現類出現了耦合,為了進一步解耦,我們就使用下面的工廠模式。
3. 工廠模式解耦
工廠的意思也就是一個批量制造同樣規格(規格也就是接口類所提供好的規范)類的類,所謂的工廠模式也就是將所有的創建對象任務交給了一個“中間人”,也就是工廠類來實現,要想使用對象,直接找工廠類,實現類必須要從工廠中取出來。對工廠模式有疑問的可以參考我之前的文章:Java 中設計模式 之 工廠模式
而要使用工廠模式進行解耦,我們需要先將創建對象交給工廠類:
// 工廠類public class BeanFactory { ? ?// 創建并返回UserDaoImpl1 ? ?public static UserDao getUserDao1(){ ? ? ? ?return new UserDaoImpl1(); ? } ? ?// 創建并返回UserDaoImpl2 ? ?public static UserDao getUserDao2(){ ? ? ? ?return new UserDaoImpl2(); ? }}將創建對象交給工廠類,調用關系就轉變為如下:
UserDao userDao = new UserDaoImpl1(); ?===> ?UserDao userDao1 = BeanFactory.getUserDao1();UserDao userDao = new UserDaoImpl2(); ?===> ?UserDao userDao2 = BeanFactory.getUserDao2();這樣一來,我們創建對象只需要調用工廠類BeanFactory中的方法即可,調用時不是直接通過接口,而是通過工廠類,將創建對象交給了工廠類,就降低了接口和實現類之間的耦合。
上面的方法雖然降低了接口和實現類之間的耦合度,但是,這樣接口和工廠類之間就產生了耦合,為了再次解耦,我們引入了反射+xml配置文件的方式進行再次解耦。
4. xml 配置 + 反射 + ?工廠解耦(IoC底層的實現)
使用xml配置文件
<bean id="userDao" class="**.UserDaoImpl">工廠類
class BeanFactory { ? ?public static UserDao getUserDao(String id) { ? ? ? ?// String className = 解析配置文件xml 拿到id對應的class ? ? ? ?// 反射 ? ? ? ?class clazz = class.forName(className); ? ? ? ?return clazz.newInstance(); ? }}可以看到,在這個工廠類中,并沒有直接像上面那樣直接new對象,而是使用了xml解析和反射方式創建對象,分析如下:
通過xml解析獲取對象中屬性的值
通過反射得到字節碼文件
通過字節碼文件創建對象
這樣的話如果我們需要改UserDao的實現類的類型,我們可以直接在配置文件中修改,就不需要修改代碼,這就是IoC的解耦。
三、IoC 原理理解
以下部分是開濤這位技術牛人對Spring框架的IOC的理解,寫得非常通俗易懂,原文地址:http://jinnianshilongnian.iteye.com/blog/1413846
1. IoC是什么
IoC:Inversion of Control(控制反轉),這不是什么技術,而是一種設計思想,在java開發中,IoC意味著將你設計好的對象交給容器,而不是傳統的在你的對象內部直接控制,如何理解好Ioc呢?理解好IoC的關鍵是要明確“誰控制誰,控制什么,為何是反轉(有反轉就應該有正轉了),哪些方面反轉了”,那我們來深入分析一下:
誰控制誰,控制什么:傳統Java SE程序設計,我們直接在對象內部通過new進行創建對象,是程序主動去創建依賴對象;而IoC是有專門一個容器來創建這些對象,即由IoC容器來控制對 象的創建;誰控制誰?當然是IoC 容器控制了對象;控制什么?那就是主要控制了外部資源獲取(不只是對象包括比如文件等)
為何是反轉,哪些方面反轉了:有反轉就有正轉,傳統應用程序是由我們自己在對象中主動控制去直接獲取依賴對象,也就是正轉;而反轉則是由容器來幫忙創建及注入依賴對象;為何是反轉?因為由容器幫我們查找及注入依賴對象,對象只是被動的接受依賴對象,所以是反轉;哪些方面反轉了?依賴對象的獲取被反轉了。
2. IoC能做什么
IoC 不是一種技術,只是一種思想,一個重要的面向對象編程的法則,它能指導我們如何設計出松耦合、更優良的程序。傳統應用程序都是由我們在類內部主動創建依賴對象,從而導致類與類之間高耦合,難于測試;有了IoC容器后,把創建和查找依賴對象的控制權交給了容器,由容器進行注入組合對象,所以對象與對象之間是 松散耦合,這樣也方便測試,利于功能復用,更重要的是使得程序的整個體系結構變得非常靈活。
其實IoC對編程帶來的最大改變不是從代碼上,而是從思想上,發生了“主從換位”的變化。應用程序原本是老大,要獲取什么資源都是主動出擊,但是在IoC/DI思想中,應用程序就變成被動的了,被動的等待IoC容器來創建并注入它所需要的資源了。
IoC很好的體現了面向對象設計法則之一—— 好萊塢法則:“別找我們,我們找你”;即由IoC容器幫對象找相應的依賴對象并注入,而不是由對象主動去找。
3. IoC和DI
DI:DI—Dependency Injection,即“依賴注入”:組件之間依賴關系由容器在運行期決定,形象的說,即由容器動態的將某個依賴關系注入到組件之中。依賴注入的目的并非為軟件系統帶來更多功能,而是為了提升組件重用的頻率,并為系統搭建一個靈活、可擴展的平臺。通過依賴注入機制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業務邏輯,而不需要關心具體的資源來自何處,由誰實現。
理解DI的關鍵是:“誰依賴誰,為什么需要依賴,誰注入誰,注入了什么”,那我們來深入分析一下:
誰依賴于誰:當然是應用程序依賴于IoC容器;
為什么需要依賴:應用程序需要IoC容器來提供對象需要的外部資源;
誰注入誰:很明顯是IoC容器注入應用程序某個對象,應用程序依賴的對象;
注入了什么:就是注入某個對象所需要的外部資源(包括對象、資源、常量數據)。
IoC和DI有什么關系呢?其實它們是同一個概念的不同角度描述,由于控制反轉概念比較含糊(可能只是理解為容器控制對象這一個層面,很難讓人想到誰來維護對象關系),所以2004年大師級人物Martin Fowler又給出了一個新的名字:“依賴注入”,相對IoC 而言,“依賴注入”明確描述了“被注入對象依賴IoC容器配置依賴對象”。
為了更好的理解,我找了一個例子:
一個人(Java實例,調用者)需要一把斧子(Java實例,被調用者)
在原始社會里,幾乎沒有社會分工;需要斧子的人(調用者)只能自己去磨一把斧子(被調用者);對應情形為:Java程序里的調用者自己創建被調用者,通常采用new關鍵字調用構造器創建一個被調用者
進入工業社會,工廠出現了,斧子不再由普通人完成,而在工廠里被生產出來,此時需要斧子的人(調用者)找到工廠,購買斧子,無須關心斧子的制造過程;對應簡單工廠設計模式,調用者只需定位工廠,無須管理被調用者的具體實現
進入“共產主義”社會,需要斧子的人甚至無須定位工廠,“坐等”社會提供即可;調用者無須關心被調用者的實現,無須理會工廠,等待Spring依賴注入
總之依賴注入的意思是你需要的東西不是由你創建的,而是第三方,或者說容器提供給你的。這樣的設計符合正交性,即所謂的松耦合。
IoC的底層原理就到這里,下一篇將講述AOP的底層原理
總結
以上是生活随笔為你收集整理的底层原理_Spring框架底层原理IoC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python可以使用二维元组吗_pyth
- 下一篇: 5 控件固定大小_【聊技术】在Andro