介紹:
AspectJ是一個面向切面編程的一個框架,它擴展了java語言,並定義了實現AOP的語法。在將.java文件編譯為.class文件時默認使用javac編譯工具,AspectJ會有一套符合java字節碼編碼規范的編譯工具來替代javac,在將.java文件編譯為.class文件時,會動態的插入一些代碼來做到對某一類特定東西的統一處理。通過預編譯方式和運行期動態代理實現在不修改源代碼的情況下給程序動態統一添加功能的技術。對業務邏輯的各個部分進行隔離,耦合度降低,提高程序的可重用性,同時提高了開發的效率。
OOP(面向對象編程)針對業務處理過程的實體及其屬性和行為進行抽象封裝,以獲得更加清晰高效的邏輯單元划分,而AOP則是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。
AOP編程的主要用途有:日志記錄,行為統計,安全控制,事務處理,異常處理,系統統一的認證、權限管理等。
AspectJ的配置很麻煩,這里使用 AspectJX 框架,框架地址:https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx
首先,先來點軟柿子捏捏,體驗一把什么叫切面編程,比較常用的埋點統計,在我們需要自己去實現埋點統計的時候,很多人是不是寫個埋點工具類,然后在每個入口的地方去添加埋點的方法,如果埋點較多會感覺很煩,如果用AspectJ怎么去實現呢,拋開業務邏輯,一切從簡
首先添加依賴
接着定義一個測試方法,testAspect,這個方法就是觸發點,只要我調用了這個方法,就統計一下
然后就開始編寫我們的AspectUtils類了,這個類需要用 @Aspect 聲明為標記類
然后在標識類下面寫切面方法
這些是什么意思呢,此處需要一段注釋
/**
@Pointcut("execution(" +//執行語句
"@com.kotlinstrong.utils.aspect.MyAnnotationOnclick" +//注解篩選
"*" + //類路徑,*為任意路徑
"*" + //方法名,*為任意方法名
"(..)" +//方法參數,'..'為任意個任意類型參數
")" +
" && " +//並集
)
@Aspect:聲明切面,標記類
@Pointcut(切點表達式):定義切點,標記方法
@Before(切點表達式):前置通知,切點之前執行
@Around(切點表達式):環繞通知,切點前后執行
@After(切點表達式):后置通知,切點之后執行
@AfterReturning(切點表達式):返回通知,切點方法返回結果之后執行
@AfterThrowing(切點表達式):異常通知,切點拋出異常時執行
* */
可以看到,我們寫的測試方法是test開頭的,before是在方法執行前切入,在onCreate里面調用方法,在運行程序后,打印出方法名稱
是不是很敢單,但是假如我要根據方法的返回值來添加邏輯定義埋點呢?腫木辦,不要慌,這都不是事,再寫一個測試方法,返回一個數值
在工具類里面需要加一個方法,從上面的注釋可以看到,需要返回值的,用 @AfterReturning,看圖說話
在注解的后面定義了一個返回參數id,這里要注意,注解上的returning標注的參數名稱要跟下面申明的參數名稱一致
然后還是一樣的打印出信息,運行一下看看
打印出1,完美,這樣埋點是不是方便多了,只要在你需要執行的方法出匹配就能自動切入埋點,自成一類,是不是感覺很興奮,原來如此簡單,但是沒結束,上面講到了埋點,還能有什么比較常規的
操作嗎。
肯定有的,根據方法名稱匹配切入有時候可能會修改方法名什么的,在一些場合肯定也不合適,這里可以自定義注解去解決,剛好我們平時跳轉頁面會做一個比較頻繁的操作,防抖,這里來實現一個防抖效果,加載一個列表,添加item點擊事件,點擊后跳轉詳情頁,如果你快速點擊,會進入多次,這顯然不是我們想要的效果,那么我們可以自定義一個注解,然后在跳轉的方法上添加注解,在切面類編寫防抖觸發,點擊間隔設置為1000毫秒
/* 防抖點擊 */
/**
* SOURCE:運行時 不存儲在編譯后的 Class 文件。
* BINARY:加載時 存儲在編譯后的 Class 文件,但是反射不可見。
* RUNTIME:編譯時 存儲在編譯后的 Class 文件,反射可見。
*/
@Retention(AnnotationRetention.RUNTIME)
/**
* CLASS:類,接口或對象,注解類也包括在內。
* ANNOTATION_CLASS:只有注解類。
* TYPE_PARAMETER:Generic type parameter (unsupported yet)通用類型參數(還不支持)。
* PROPERTY:屬性。
* FIELD:字段,包括屬性的支持字段。
* LOCAL_VARIABLE:局部變量。
* VALUE_PARAMETER:函數或構造函數的值參數。
* CONSTRUCTOR:僅構造函數(主函數或者第二函數)。
* FUNCTION:方法(不包括構造函數)。
* PROPERTY_GETTER:只有屬性的 getter。
* PROPERTY_SETTER:只有屬性的 setter。
* TYPE:類型使用。
* EXPRESSION:任何表達式。
* FILE:文件。
* TYPEALIAS:@SinceKotlin("1.1") 類型別名,Kotlin1.1已可用。
*/
@Target(AnnotationTarget.FUNCTION)
annotation class MyAnnotationOnclick(
/** 點擊間隔時間 */
val value: Long = 1000
)
這里一個注解類就完成了,然后在編寫一個測試方法,在方法里去跳轉一個頁面,然后在你的點擊事件里調用這個跳轉方法
接下來到我們的切面類去定義一個切點
這里識別注解標識的方法,告訴代碼注入工具,在何處注入一段特定帶條件的代碼的表達式,此處的條件就是我們定義的注解,然后在編寫我們的切入方法
此處獲匹配到注解方法,然后調用了一個ClickUtils類去做防抖操作
運行你的程序發現,快速點擊的時候只會觸發一次了,只需要在你操作的跳轉方法里添加一個注解就可以達到防抖效果,nice,扶我起來,我還能學
說到切面編程就不得不說登錄了,一般app就是兩種方式,先登錄在進入,先進入,在檢查讓你登錄,那么如果是先進入瀏覽,然后在檢測讓用戶登錄是不是也需要在多個地方去判斷呢,這里是不是也一樣,可以用Aspect去做呢,拿起鍵盤就是一頓ctrl+c
還是一樣的套路,首先定義一個注解
然后我需要在打開詳情頁的時候去檢測,如果沒有登錄的話就直接跳轉到登錄頁面去
在到工具類里寫切面表達式跟方法,這里用最簡單的方式來實現效果,真的登錄肯定不會這么簡單
運行后,點擊詳情,會發現打開了一個詳情后再次打開了一個登錄頁面,這里復用也是很方便,當然,它還有很多作用,比如計算方法的耗時等等
不行了,學不動了,趕緊掐人中
Aspects不是萬能的,但是有了它可以對我們的開發帶來極大的方便,這里附上Kotlin項目地址