今天是五一收假以來的第一天,距離下一週一共還有四天,這周主要是對Spring的重學習。這四天內我將從以下幾個角度進行分析和理解。
(1)AOP的理解和分析
(2)IOC的理解和分析
(3)對bean的理解和分析
(4)spring配置文件的理解和分析
首先今天對AOP的理解和分析,對aop的理解也分開闡述,對一個技術的思考,基本上都是從上學時候課本闡述一個新知識的順序進行的。 第一:什麼是AOP?
第二:爲什麼要引入AOP?或者是AOP解決了什麼問題?
第三:如何簡單的實現AOP?
第四:AOP對我們寫代碼時候的思考和幫助是什麼?
現在,開始對AOP進行闡述,
1 什麼是AOP?
1.1 概念介紹
Spring的使命是簡化Java代碼開發,aop作爲Spring的一個子模塊,也不例外。
AOP 是 Aspect Oriented Programming(面向切面編程) 的簡稱,和OOP(面向對象編程)一樣是一種編程思想,是對OOP的一種補充。
如何理解什麼是AOP呢?以日誌爲例,在很多管理系統,比如訂單系統、推送系統等等都需要把日誌記錄下來。如果每個業務邏輯裏面都寫日誌的相關代碼,那就重複太多了。
乾脆把日誌的相關邏輯代碼,統一封裝起來。然後在需要的地方嵌入即可。AOP也主要就是做嵌入這件事的。看下面這張圖。
新增訂單編輯訂單取消訂單推送訂單日誌事務
AOP旨在將橫切關注點(crosscutting concern)從業務主體邏輯中進行剝離,實現關注點分離,以提高程序的模塊化程度(及業務模塊只需關注業務邏輯,無需關注日誌、安全、事務等通用邏輯)
上面提到了一些名詞,比如說,切面、關注點、橫切等,下面對這些名詞進行解釋。
1.2 名詞解釋
-
AOP有自己的一套術語,我們必須瞭解一下這些行話,才能更好地理解AOP。爲了方便大家理解,下面將用課代表收作業作爲例子。
-
通知 (Advice)
定義了在收作業前後需要做的事。常見的通知類型有:before、after、after-returning、around等。
-
連接點 (JoinPoint)
連接點指程序運行時允許插入切面的一個點,可以是一個函數、一個包路徑、一個類、或者拋出的異常。有點類似於可以收作業的時間點。
-
切點(PointCut)
切點用於定義切面的位置,也就是捕獲哪些連接點的調用然後執行"通知"的操作(什麼地點)。
-
切面(Aspect)
切面是切點和通知的聚合,定義了在哪一個切點做什麼通知。
-
目標對象( Target )
指被切面織入的對象。
-
引入(Introduction)
引入允許我們向現有的類添加新方法或屬性。
-
織入(Weaving)
織入是把切面應用到切點對應的連接點的過程。切面在指定連接點被織入到目標對象中。
-
具體關係使用圖形化表示是:
2 爲什麼要引入AOP?
上面是定義,引入AOP的原因肯定是可以解決目前開發中存在的某些痛點:
(1)目前的開發當中,相互之間都是模塊化開發,使用AOP可以有效的實現模塊化的思路。
(2)將輔助邏輯(日誌、安全、監控等)從業務主體邏輯中進行剝離,同步進行開發。
AOP是一種思想,這種思想是把一些業務邏輯剝離開,然後按照主業務邏輯進行組合,最後達到想要的功能邏輯。
3 如何簡單的實現AOP?
3.1 AOP編程思路
本圖是一個簡單的思路。
明確需求創建切面類定義切點定義通知思考:要在哪個方法的什麼時候做什麼事(方法前?方法後? 還是around ?)即選擇哪個連接點進行執行通知在切點附近(before?after?) 做什麼操作
下面定義一個日誌的簡單案例,實現AOP。使用的是原始的註解方式:
3.2 案例實現AOP
3.2.1 明確需求
在某個方法上加上@FddLog,就會在執行這個方法的前後,自動輸出相應的信息。下面以把大象放進冰箱爲例子進行演示:
3.2.2 基本接口和實現
public interface ElephentToRe{
public void toRe();
}
實現類如下:
public class ElephentToReImpl implements ElephentToRe{
public void toRe() {
System.out.println("把大象放冰箱");
}
}
3.2.3 定義切面和通知
public class ElephentToReHelper{
public void beforeElephentToRe(){
System.out.println("把冰箱門打開");
}
public void afterElephentToRe(){
System.out.println("把冰箱門關上");
}
}
配置就好了
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<!-- 定義通知內容,也就是切入點執行前後需要做的事情 -->
<bean id="elephentToReHelper" class="com.fdd.bean.ElephentToReHelper"></bean>
<!-- 定義被代理者 -->
<bean id="elephentToReImpl" class="com.fdd.bean.ElephentToReImpl"></bean>
<aop:config>
<aop:aspect ref="elephentToReHelper">
<aop:before method="beforeElephentToRe" pointcut="execution(* *.toRe(..))" />
<aop:after method="afterElephentToRe" pointcut="execution(* *.toRe(..))" />
</aop:aspect>
</aop:config>
</beans>
3.2.4 測試看效果
public class Test {
public static void main(String[] args){
@SuppressWarnings("resource")
ApplicationContext appCtx = new FileSystemXmlApplicationContext("application.xml");
ElephentToRe elephentToReImpl = (ElephentToRe)appCtx.getBean("elephentToReImpl");
elephentToReImpl.toRe();
}
}
上面的這種方法是通過純粹的POJO切面來完成的。實現方式也比較簡單。
4 我對AOP思想的看法
任何新技術的出現都是爲了解決目前開發中存在的某些痛點。對於aop來說,其主要是把一些功能代碼進行抽象封裝,和主業務邏輯代碼進行剝離。在需要的地方進行織入即可。
我的看法是
(1)在平時開發代碼的時候,完全可以把一些常見的,常用的功能代碼進行封裝,儘量做到動態配置。不同的功能模塊只需要進行織入即可。
(2)定義業務邏輯的模板,比如說如果要解決某一個業務功能,如果頁面類似,可以按照基本的框架進行組合,然後使用配置平臺進行可控化配置即可。