android aspectj 参数,在Android项目中使用AspectJ
什么是AOP
AOP是 Aspect Oriented Programming 的縮寫,即面向切面編程,和日常遇到的面向?qū)ο驩OP編程不同的是,OOP是將功能模塊化對(duì)象化,AOP是針對(duì)同一類的問題統(tǒng)一化處理。例如作日志埋點(diǎn),性能監(jiān)控,動(dòng)態(tài)權(quán)限控制等。android
AspectJ
AspectJ其實(shí)是對(duì)AOP編程的實(shí)踐,目前還有不少的AOP實(shí)現(xiàn),如ASMDex,但筆者選用的是AspectJ。git
在Android項(xiàng)目中使用AspectJ
若是使用原生AspectJ在項(xiàng)目中配置會(huì)很是麻煩,在GitHub上有個(gè)開源的SDK gradle_plugin_android_aspectjx基于gradle配置便可。github
接入說明
請(qǐng)自行查看開源項(xiàng)目中的接入配置過程編程
AspectJ 之 Join Points介紹
Join Points在AspectJ中是關(guān)鍵的概念。Join Points能夠看作是程序運(yùn)行時(shí)的一個(gè)執(zhí)行點(diǎn),好比:一個(gè)函數(shù)的調(diào)用能夠看作是個(gè)Join Points,至關(guān)于代碼切入點(diǎn)。但在AspectJ中,只有下面幾種執(zhí)行點(diǎn)是認(rèn)為是Join Points:app
Join Points
說明
實(shí)例
method call
函數(shù)調(diào)用
好比調(diào)用Log.e(),這是一個(gè)個(gè)Join Point
method execution
函數(shù)執(zhí)行
好比Log.e()的執(zhí)行內(nèi)部,是一處Join Points。注意這里是函數(shù)內(nèi)部
constructor call
構(gòu)造函數(shù)調(diào)用
和method call 相似
constructor execution
構(gòu)造函數(shù)執(zhí)行
和method execution 相似
field get
獲取某個(gè)變量
好比讀取DemoActivity.debug成員
field set
設(shè)置某個(gè)變量
好比設(shè)置DemoActivity.debug成員
pre-initialization
Object在構(gòu)造函數(shù)中作的一些工做。
-
initialization
Object在構(gòu)造函數(shù)中作的工做。
-
static initialization
類初始化
好比類的static{}
handler
異常處理
好比try catch 中,對(duì)應(yīng)catch內(nèi)的執(zhí)行
advice execution
這個(gè)是AspectJ 的內(nèi)容
-
Pointcuts 介紹
一個(gè)程序會(huì)有多個(gè)Join Points,即便同一個(gè)函數(shù),也還分為call 和 execution 類型的Join Points,但并非全部的Join Points 都是咱們關(guān)心的,Pointcuts 就是提供一種使得開發(fā)者可以值選擇所需的JoinPoints的方法。ide
Advice
Advice就是咱們插入的代碼能夠以何種方式插入,有Before 還有 After、Around。 下面看個(gè)例子:模塊化
@Before(“execution(* android.app.Activity.on**(..)))”)
public void onActivityMethodBefore(JoinPoint joinPoint) throws Throwable{
}
這里會(huì)分紅好幾個(gè)部分,咱們依次來看:函數(shù)
@Before: Advice, 也就是具體的插入點(diǎn)
execution:處理Join Point的類型,例如call、execution
(* android.app.Activity.on**(..)): 這個(gè)是最重要的表達(dá)式,第一個(gè)*表示返回值,*表示返回值為任意類型,后面這個(gè)就是典型的包名路徑,其中能夠包含 *來進(jìn)行通配,幾個(gè) *沒有區(qū)別。同時(shí)這里能夠經(jīng)過&&、||、!來進(jìn)行條件組合。()表明這個(gè)方法的參數(shù),你能夠指定類型,例如android.os.Bundle,或者 (..) 這樣來表明任意類型、任意個(gè)數(shù)的參數(shù)。
public void onActivityMehodBefore: 實(shí)際切入的代碼。
Before 和 After 其實(shí)仍是很好理解的,也就是在Pointcuts以前和以后,插入代碼,那么Android呢,從字面含義上來說,也就是在方法先后各插入代碼,他包含了 Before和 After 的所有功能,代碼以下:
@(“execution(* com.xys.aspectjxdemo.MainActivity.testAOP()))”)
public void onActivityMethodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
String key = proceedingJoinPoint.getSignature().toString();
Log.d(TAG,”onActivityMethodAroundFirst:”+key);
proceedingJoinPoint.proceed();
Log.d(TAG,”onActivityMethodAroundSecond:”+key);
}
以上代碼中,proceedingJoinPoint.proceed()表明執(zhí)行原始的方法,在這以前、以后,均可以進(jìn)行各類邏輯處理。
自定義Pointcuts
自定義Pointcuts可讓咱們更加精準(zhǔn)的切入一個(gè)或多個(gè)指定的切入點(diǎn)。 首先咱們要定義一個(gè)注解類
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface DebugTrace {
}
在須要插入代碼的地方加入這個(gè)注解,例如在MainActivity中加入:
public class MainActivity extends AppCompatActivity{
final String TAG = MainActivity.class.getSimpleName();
@Override
protedcted void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
logTest();
}
@DebugTrace
public void logTest(){
Log.e(TAG,”log test");
}
}
最后建立切入代碼
@Pointcut(“execution(@com.kun.aspectjtest.aspect.DebugTrace * *..*.*(..))”)
public void DebugTraceMethod(){}
@Before(“DebugTraceMethod()”)
public void beforeDebugTraceMethod(JoinPoint joinPoint) throws Throwable{
String key = joinPoint.getSignature().toString();
Log.e(TAG, “beforeDebugTraceMethod:”+key);
}
Call
在AspectJ的切入點(diǎn)表達(dá)式中,咱們前面都是使用的execution,實(shí)際上還有一種類型—call,那么這兩種語法有什么區(qū)別呢?對(duì)call來講:
Call (Before)
Pointcut{
Pointcut Method
}
Call (After)
對(duì)Execution來講:
Pointcut{
execution (Before)
Pointcut Method
execution (After)
}
Withincode
這個(gè)語法一般來進(jìn)行一些切入點(diǎn)條件的過濾,做更加精確的切入控制,以下:
public class MainActivity extends AppCompatActivity{
final String TAG = MainActivity.class.getSimpleName();
@Orveride
protected void onCreate(Bundle savedInstanceState){
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
aspectJ1();
aspectJ2();
aspectJ3();
}
public void aspectJTest(){
Log.e(TAG,”execute aspectJTest");
}
public void aspectJ1(){
aspectJTest();
}
public void aspectJ2(){
aspectJTest();
}
public void aspectJ3(){
aspectJTest();
}
}
aspectJ1(),aspectJ2(),aspectJ3()都調(diào)用了aspectJTest方法,但只想在aspectJ2調(diào)用aspectJTest時(shí)插入代碼,這個(gè)時(shí)候就須要使用到Pointcut和withcode組合的方式,來精肯定位切入點(diǎn)。
@Pointcut(“(call(* *..aspectJTest()))&&withincode(* *..aspectJ2())”)
public void invokeAspectJTestInAspectJ2(){
}
@Before(“invokeAspectJTestInAspectJ2()”)
public void beforeInvokeaspectJTestInAspectJ2(JoinPoint joinPoint) throws Throwable{
Log.e(TAG,”method:”+getMethodName(joinPoint).getName());
}
private MethodSignature getMethodName(JoinPoint joinPoint){
if(joinPoint == null) return null;
return (MethodSignature) joinPoint.getSignature();
}
execution 語法
execution()是最經(jīng)常使用的切點(diǎn)函數(shù),其語法以下所示: 例以下面這段語法: @Around(“execution(* *..MainActivity+.on*(..))") 整個(gè)表達(dá)式能夠分為五個(gè)部分:
execution()是表達(dá)式主體
第一個(gè)*號(hào)表明返回類型,*號(hào)表明全部的類型。
包名 表示須要攔截的包名,這里使用*.表明匹配全部的包名。
第二個(gè)*號(hào)表示類名,后面跟.MainActivity是指具體的類名叫MainActivity。
*(..) 最后這個(gè)星號(hào)表示方法名,+.表明具體的函數(shù)名,*號(hào)通配符,包括括弧號(hào)里面表示方法的參數(shù),兩個(gè)dot表明任意參數(shù)。
遇到的錯(cuò)誤
如下錯(cuò)誤可使用gradle2.2.3解決,因?yàn)槟壳斑€不適配gradle3.0致使的
Error:Execution failed for task ':app:transformClassesWithDexBuilderForDebug'.
> Unexpected scopes found in folder '/Users/ram/WorkSpace/AndroidWorkSpace/MyDemo/app/build/intermediates/transforms/AspectTransform/debug'. Required: PROJECT, SUB_PROJECTS, EXTERNAL_LIBRARIES. Found: EXTERNAL_LIBRARIES, PROJECT, PROJECT_LOCAL_DEPS, SUB_PROJECTS, SUB_PROJECTS_LOCAL_DEPS
總結(jié)
以上是生活随笔為你收集整理的android aspectj 参数,在Android项目中使用AspectJ的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uni-app实现验证码登录-云之讯
- 下一篇: 华硕支持2003服务器主板,驱动天空 -