面試被問了幾百遍的 IoC 和 AOP ,還在傻傻搞不清楚?


這篇文章會從下面從以下幾個問題展開對 IoC & AOP 的解釋

  • 什么是 IoC?
  • IoC 解決了什么問題?
  • IoC 和 DI 的區別?
  • 什么是 AOP?
  • AOP 解決了什么問題?
  • AOP 為什么叫做切面編程?

首先聲明:IoC & AOP 不是 Spring 提出來的,它們在 Spring 之前其實已經存在了,只不過當時更加偏向於理論。Spring 在技術層次將這兩個思想進行了很好的實現。

什么是 IoC

IoC (Inversion of control )控制反轉/反轉控制。它是一種思想不是一個技術實現。描述的是:Java 開發領域對象的創建以及管理的問題。

例如:現有類 A 依賴於類 B

  • 傳統的開發方式 :往往是在類 A 中手動通過 new 關鍵字來 new 一個 B 的對象出來
  • 使用 IoC 思想的開發方式 :不通過 new 關鍵字來創建對象,而是通過 IoC 容器(Spring 框架) 來幫助我們實例化對象。我們需要哪個對象,直接從 IoC 容器里面過去即可。

從以上兩種開發方式的對比來看:我們 “喪失了一個權力” (創建、管理對象的權力),從而也得到了一個好處(不用再考慮對象的創建、管理等一系列的事情)

為什么叫控制反轉

控制 :指的是對象創建(實例化、管理)的權力

反轉 :控制權交給外部環境(Spring 框架、IoC 容器)

IoC 解決了什么問題

IoC 的思想就是兩方之間不互相依賴,由第三方容器來管理相關資源。這樣有什么好處呢?

  1. 對象之間的耦合度或者說依賴程度降低;
  2. 資源變的容易管理;比如你用 Spring 容器提供的話很容易就可以實現一個單例。

例如:現有一個針對 User 的操作,利用 Service 和 Dao 兩層結構進行開發

在沒有使用 IoC 思想的情況下,Service 層想要使用 Dao 層的具體實現的話,需要通過 new 關鍵字在UserServiceImpl 中手動 new 出 IUserDao 的具體實現類 UserDaoImpl(不能直接 new 接口類)。

很完美,這種方式也是可以實現的,但是我們想象一下如下場景:

開發過程中突然接到一個新的需求,針對對IUserDao 接口開發出另一個具體實現類。因為 Server 層依賴了IUserDao的具體實現,所以我們需要修改UserServiceImpl中 new 的對象。如果只有一個類引用了IUserDao的具體實現,可能覺得還好,修改起來也不是很費力氣,但是如果有許許多多的地方都引用了IUserDao的具體實現的話,一旦需要更換IUserDao 的實現方式,那修改起來將會非常的頭疼。

img

使用 IoC 的思想,我們將對象的控制權(創建、管理)交有 IoC 容器去管理,我們在使用的時候直接向 IoC 容器 “要” 就可以了

img

IoC 和 DI 別再傻傻分不清楚

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 。

img

老馬的大概意思是 IoC 太普遍並且不表意,很多人會因此而迷惑,所以,使用 DI 來精確指名這個模式比較好。

什么是 AOP

AOP:Aspect oriented programming 面向切面編程,AOP 是 OOP(面向對象編程)的一種延續。

下面我們先看一個 OOP 的例子。

例如:現有三個類,HorsePigDog,這三個類中都有 eat 和 run 兩個方法。

通過 OOP 思想中的繼承,我們可以提取出一個 Animal 的父類,然后將 eat 和 run 方法放入父類中,HorsePigDog通過繼承Animal類即可自動獲得 eat() 和 run() 方法。這樣將會少些很多重復的代碼。

img

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"); } } 

這部分重復的代碼,一般統稱為 橫切邏輯代碼

img

橫切邏輯代碼存在的問題:

  • 代碼重復問題
  • 橫切邏輯代碼和業務代碼混雜在一起,代碼臃腫,不變維護

AOP 就是用來解決這些問題的

AOP 另辟蹊徑,提出橫向抽取機制,將橫切邏輯代碼和業務邏輯代碼分離

img

代碼拆分比較容易,難的是如何在不改變原有業務邏輯的情況下,悄無聲息的將橫向邏輯代碼應用到原有的業務邏輯中,達到和原來一樣的效果。

AOP 解決了什么問題

通過上面的分析可以發現,AOP 主要用來解決:在不改變原有業務邏輯的情況下,增強橫切邏輯代碼,根本上解耦合,避免橫切邏輯代碼重復。

AOP 為什么叫面向切面編程

 :指的是橫切邏輯,原有業務邏輯代碼不動,只能操作橫切邏輯代碼,所以面向橫切邏輯

 :橫切邏輯代碼往往要影響的是很多個方法,每個方法如同一個點,多個點構成一個面。這里有一個面的概念

 

PS: Spring

AOP編程使用

注解版本實現AOP

@Aspect 指定一個類為切面類

@Pointcut("execution(* com.itmayiedu.service.UserService.add(..))")  指定切入點表達式

@Before("pointCut_()") 前置通知: 目標方法之前執行

@After("pointCut_()") 后置通知:目標方法之后執行(始終執行)

@AfterReturning("pointCut_()")  返回后通知: 執行方法結束前執行(異常不執行)

@AfterThrowing("pointCut_()") 異常通知:  出現異常時候執行

@Around("pointCut_()") 環繞通知: 環繞目標方法執行

 

AOP編程應用場景

 

日志記錄,性能統計,安全控制,事務處理,異常處理。

 

 

1.spring事務基於AOP環繞通知和異常通知實現的。

2.spring事務分為:編程式事務、聲明式事務。spring底層使用編程式事務+AOP技術進行包裝的=聲明式事務。

AOP作用:定義一個切入點,攔截切入點的方法,攔截到方法后,可以在方法之前或者之后進行處理。

作用:簡化重復代碼。

應用場景:事務底層實現、日志管理、權限控制等。

 

Spring AOP 圖形詳細介紹:

https://www.cnblogs.com/xichji/p/11835785.html

作者: 王春天
出處: http://www.cnblogs.com/spring_wang/
Email: spring_best@yeah.net
QQ交流:903639067 
QQ群:322581894



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM