開篇廢話
真心非常感謝有這么一個五一假期恩溅,自己能夠挪出來這么一大塊的時間來好好學習,感覺無比幸福
近期谓娃,由于一個人的時間畢竟有限暴匠,工作上,學習上傻粘,生活上,都占用了太多時間帮掉,實在是沒有抽出來時間好好整理自己的一些知識點弦悉,更糟糕的是,本來想到了不少的知識點想分享的蟆炊,到今天想分享的時候稽莉,已經有點記不起哪些是當時想要分享的了,對此涩搓,我應該在一個日志工具中記錄一下污秆,免得出現(xiàn)現(xiàn)在這種情況。
近期花了一筆不少的錢報了一個在線進階的班昧甘,跟著老師系統(tǒng)的把Android知識學習一遍良拼,個人覺得還是挺值得的。因此充边,想著能把自己學到冰山一角整理一下庸推,鞏固一下自己的記憶,也供我們開發(fā)者一些參考浇冰。
廢話就不多說了贬媒,今天就簡單介紹一下AOP編程思想吧。肘习。际乘。
技術詳情
1. 什么是AOP
官方釋義:面向切面編程,看到這個解釋漂佩,其實對于沒有接觸過AOP的人來說脖含,依然是一臉懵逼。
我們可以聯(lián)想一下我們自己使用最多的一種思想投蝉,就是面向對象編程器赞。
然后相較于面向對象,面向切面編程就是在多個功能中嵌入但又不是那個功能模塊的一個主要功能墓拜,舉個例子港柜,大概是這樣:
A模塊負責網絡訪問模塊,B模塊負責本地數據庫模塊,C模塊負責日志打印模塊夏醉,那么A和B模塊里面都會嵌入
C模塊爽锥,也就是都需要打印一些日志,供我們調試或者記錄畔柔,這個時候氯夷,我們就可以把C模塊當做A模塊和B模塊的一個共同切面,
而不是在A模塊或者B模塊的各個地方都寫上的日志靶擦,而是集中在C模塊中進行管理腮考。
這么說可能還是不怎么好理解,那么我們就用代碼的方式來比較說明吧
2. AOP的簡易使用
首先玄捕,我們實現(xiàn)一個簡易的功能:計算某一段代碼運行的時長踩蔚,這樣,我們可以知道到底是哪一個地方或者方法耗時比較多枚粘,可以有針對的對我們的app進行優(yōu)化馅闽。
針對這個功能,我們應該在一段代碼運行前馍迄,記錄一個時間點福也,運行完,再用當前時間減去運行前的時間點攀圈,就會得出暴凑,這段代碼運行的時長。
實現(xiàn)代碼如下:
/**
* 模擬耗時操作:查詢數據庫
* @param view
*/
public void onFetchDatabase(View view){
long begin = System.currentTimeMillis();
SystemClock.sleep(new Random().nextInt(2000));
long duration = System.currentTimeMillis() - begin;
Log.i(TAG,"本次查詢數據庫耗時: " + duration + "ms");
}
/**
* 模擬耗時操作:訪問網絡服務器
* @param view
*/
public void doNetAction(View view){
long begin = System.currentTimeMillis();
SystemClock.sleep(new Random().nextInt(2000));
long duration = System.currentTimeMillis() - begin;
Log.i(TAG,"本次訪問網絡服務器耗時: " + duration + "ms");
}
/**
* 模擬耗時操作:保存本地文件
* @param view
*/
public void saveLocalFile(View view){
long begin = System.currentTimeMillis();
SystemClock.sleep(new Random().nextInt(2000));
long duration = System.currentTimeMillis() - begin;
Log.i(TAG,"本次保存本地文件耗時: " + duration + "ms");
}
/**
* 模擬耗時操作:做其他操作
* @param view
*/
public void onDoOtherSomething(View view){
long begin = System.currentTimeMillis();
SystemClock.sleep(new Random().nextInt(2000));
long duration = System.currentTimeMillis() - begin;
Log.i(TAG,"本次操作耗時: " + duration + "ms");
}
從以上代碼赘来,我們可以看出來搬设,在每一個方法里面,都必須有一段相同的代碼來計算耗時撕捍,當我們的功能模塊很多很多的時候拿穴,這種寫法就會很蛋疼了,到時候后期維護也不得了忧风,這還只是單純的一個耗時統(tǒng)計功能而已默色,如果還有其他類似的功能呢?
那么狮腿,下面我們使用AOP的思想來完成這個功能腿宰,其中的好處,自行體會缘厢。
涉及的知識點有:
1.自定義注解的簡易使用
2.AspectJ的引入(可以理解為引入一個jar包)吃度,作為切面處理的一個工具類
首先創(chuàng)建一個自定義注解CalculateDuration :
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CalculateDuration {
String value();
}
然后引入AspecgJ編譯器(一種與javac類似的編譯器,可以不用深究贴硫,能用就行)椿每,具體使用伊者,可以查看我的github源碼中的app模塊的gradle配置
接著就是實現(xiàn)切面的邏輯代碼:
@Aspect
public class CalculateDurationAspect {
//TODO 定義切面的規(guī)則
//TODO 1.就是原來的應用中,哪些注釋的地方放到當前切面進行處理
//execution(注解名 注解用的地方)
@Pointcut("execution(@senduo.com.aopdemo.annotation.CalculateDuration * *(..) )")
public void methodAnonotatedWithCalculateDuration(){}
//TODO 2.對進入切面的內容如何處理
//advice
//@Before() 在切入點之前運行
//After() 在切入點之后運行
/ /Around() 在切入點前后運行
@Around("methodAnonotatedWithCalculateDuration()")
public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable{
//獲取切面簽名
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//根據簽名 獲取更多的信息
String className = methodSignature.getDeclaringType().getSimpleName();//類名
String methodName = methodSignature.getName();//方法名
String funName = methodSignature.getMethod().getAnnotation(CalculateDuration.class).value();//功能名
long begin = System.currentTimeMillis();
Object result = joinPoint.proceed();//這里就是原先處理的邏輯
long durarion = System.currentTimeMillis() - begin;
Log.d("senduo",className + " " + methodName + " " + "本次" + funName + "耗時:" + durarion + "ms");
return result;
}
}
通過以上切面的實現(xiàn)间护,在我們最開始的那段代碼就變成一下的樣子了:
@CalculateDuration("查詢數據庫")
public void onFetchDatabase(View view){
SystemClock.sleep(new Random().nextInt(2000));
}
@CalculateDuration("訪問網絡服務器")
public void doNetAction(View view){
SystemClock.sleep(new Random().nextInt(2000));
}
@CalculateDuration("保存本地文件")
public void saveLocalFile(View view){
SystemClock.sleep(new Random().nextInt(2000));
}
@CalculateDuration("做其他操作")
public void onDoOtherSomething(View view){
SystemClock.sleep(new Random().nextInt(2000));
}
這樣亦渗,在這個地方,我們只需要關注自身的功能實現(xiàn)汁尺,而不需要插入那么多亂七八糟的代碼
關于此項目的源代碼法精,在文章最后,會提供github地址痴突,歡迎star
干貨總結
以上搂蜓,是這一次關于AOP編程思想知識的一個簡易整理,如果對于這一塊有興趣辽装,可以多花點時間帮碰,好好去研究,我這邊暫時也只能進行一個簡單陳述如迟。
此文章的作用有如下幾點:
1.認識一下AOP編程
2.能夠優(yōu)化我們工作中的一些全局業(yè)務(比如性能檢測,權限驗證攻走,資源釋放殷勘,用戶行為統(tǒng)計等)
3.服務器那邊可通過AOP思想進行數據挖掘,數據分析
以下是此demo的源碼: