「本文已經收錄進個人 79K Star 的 Java 開源項目 JavaGuide:github.com/Snailclimb/… (「Java學習+面試指南」一份涵蓋大部分Java程序員所須要掌握的核心知識。)html
相關閱讀:完結撒花!Github接近80K點讚的Java面試指南來啦!git
本文爲讀者投稿!程序員
這篇文章會從下面從如下幾個問題展開對 IoC & AOP 的解釋github
首先聲明:IoC & AOP 不是 Spring 提出來的,它們在 Spring 以前其實已經存在了,只不過當時更加偏向於理論。Spring 在技術層次將這兩個思想進行了很好的實現。web
IoC (Inversion of control )控制反轉/反轉控制。它是一種思想不是一個技術實現。描述的是:Java 開發領域對象的建立以及管理的問題。面試
例如:現有類 A 依賴於類 B編程
從以上兩種開發方式的對比來看:咱們 「喪失了一個權力」 (建立、管理對象的權力),從而也獲得了一個好處(不用再考慮對象的建立、管理等一系列的事情)框架
控制 :指的是對象建立(實例化、管理)的權力編輯器
反轉 :控制權交給外部環境(Spring 框架、IoC 容器)ide
IoC 的思想就是兩方之間不互相依賴,由第三方容器來管理相關資源。這樣有什麼好處呢?
例如:現有一個針對 User 的操做,利用 Service 和 Dao 兩層結構進行開發
在沒有使用 IoC 思想的狀況下,Service 層想要使用 Dao 層的具體實現的話,須要經過 new 關鍵字在UserServiceImpl
中手動 new 出 IUserDao
的具體實現類 UserDaoImpl
(不能直接 new 接口類)。
很完美,這種方式也是能夠實現的,可是咱們想象一下以下場景:
開發過程當中忽然接到一個新的需求,針對對IUserDao
接口開發出另外一個具體實現類。由於 Server 層依賴了IUserDao
的具體實現,因此咱們須要修改UserServiceImpl
中 new 的對象。若是隻有一個類引用了IUserDao
的具體實現,可能以爲還好,修改起來也不是很費力氣,可是若是有許許多多的地方都引用了IUserDao
的具體實現的話,一旦須要更換IUserDao
的實現方式,那修改起來將會很是的頭疼。
使用 IoC 的思想,咱們將對象的控制權(建立、管理)交有 IoC 容器去管理,咱們在使用的時候直接向 IoC 容器 「要」 就能夠了
IoC(Inverse of Control:控制反轉)是一種設計思想 或者說是某種模式。這個設計思想就是 將本來在程序中手動建立對象的控制權,交由 Spring 框架來管理。 IoC 在其餘語言中也有應用,並不是 Spring 特有。IoC 容器是 Spring 用來實現 IoC 的載體, IoC 容器實際上就是個 Map(key,value),Map 中存放的是各類對象。
IoC 最多見以及最合理的實現方式叫作依賴注入(Dependency Injection,簡稱 DI)。
而且,老馬(Martin Fowler)在一篇文章中提到將 IoC 更名爲 DI,原文以下,原文地址:https://martinfowler.com/articles/injection.html 。
老馬的大概意思是 IoC 太廣泛而且不表意,不少人會所以而迷惑,因此,使用 DI 來精確指名這個模式比較好。
AOP:Aspect oriented programming 面向切面編程,AOP 是 OOP(面向對象編程)的一種延續。
下面咱們先看一個 OOP 的例子。
例如:現有三個類,Horse
、Pig
、Dog
,這三個類中都有 eat 和 run 兩個方法。
經過 OOP 思想中的繼承,咱們能夠提取出一個 Animal 的父類,而後將 eat 和 run 方法放入父類中,Horse
、Pig
、Dog
經過繼承Animal
類便可自動得到 eat()
和 run()
方法。這樣將會少些不少重複的代碼。
OOP 編程思想能夠解決大部分的代碼重複問題。可是有一些問題是處理不了的。好比在父類 Animal 中的多個方法的相同位置出現了重複的代碼,OOP 就解決不了。
/** * 動物父類 */ public class Animal { /** 身高 */ private String height; /** 體重 */ private double weight; public void eat() { // 性能監控代碼 long start = System.currentTimeMillis(); // 業務邏輯代碼 System.out.println("I can eat..."); // 性能監控代碼 System.out.println("執行時長:" + (System.currentTimeMillis() - start)/1000f + "s"); } public void run() { // 性能監控代碼 long start = System.currentTimeMillis(); // 業務邏輯代碼 System.out.println("I can run..."); // 性能監控代碼 System.out.println("執行時長:" + (System.currentTimeMillis() - start)/1000f + "s"); } } 複製代碼
這部分重複的代碼,通常統稱爲 橫切邏輯代碼。
橫切邏輯代碼存在的問題:
AOP 就是用來解決這些問題的
AOP 另闢蹊徑,提出橫向抽取機制,將橫切邏輯代碼和業務邏輯代碼分離
代碼拆分比較容易,難的是如何在不改變原有業務邏輯的狀況下,悄無聲息的將橫向邏輯代碼應用到原有的業務邏輯中,達到和原來同樣的效果。
經過上面的分析能夠發現,AOP 主要用來解決:在不改變原有業務邏輯的狀況下,加強橫切邏輯代碼,根本上解耦合,避免橫切邏輯代碼重複。
切 :指的是橫切邏輯,原有業務邏輯代碼不動,只能操做橫切邏輯代碼,因此面向橫切邏輯
面 :橫切邏輯代碼每每要影響的是不少個方法,每一個方法如同一個點,多個點構成一個面。這裏有一個面的概念
本文使用 mdnice 排版