- 為何想到AOP
- AOP
- 項(xiàng)目完整代碼
- 如何接入
- AspectJ
- 具體實(shí)現(xiàn)
- 自定義切點(diǎn)
- 切面
- 使用如何
- 獲取切點(diǎn)中的自定義的值
- 如何獲取方法中的參數(shù)
- 反編譯結(jié)果
為何想到AOP
在移動(dòng)端開發(fā)中隅忿,我們總能遇到這樣的需求:跳轉(zhuǎn)到下一個(gè)界面前判斷一下用戶的登陸狀態(tài)昧辽,若登陸了,則跳轉(zhuǎn)到下一界面,否則栋荸,跳轉(zhuǎn)到登陸界面菇怀。Activity跳轉(zhuǎn)代碼我們肯定是爛熟于心的。
if(isLogin){
Intent intent = new Intent(context,NextActivity);
startActivity(intent);
}else{
Intent intent = new Intent(context,LoginActivity);
startActivity(intent);
}
搞定晌块。若是項(xiàng)目只有幾個(gè)Activity的話敏释,這樣寫完全沒什么問題,但是摸袁,一旦我們的項(xiàng)目有幾十個(gè)Activity的話钥顽。。靠汁。再加上后續(xù)如果需要網(wǎng)絡(luò)判斷啊蜂大,Log啊之類的需求
要是有什么黑科技像把刀一樣每次跳轉(zhuǎn)前切開代碼把這些前置邏輯判斷自動(dòng)添加進(jìn)去就好了。
嘿嘿嘿蝶怔,這還真的有奶浦,面向切面編程AOP!
AOP
AOP是通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)踢星。
AOP可以對所謂的業(yè)務(wù)邏輯進(jìn)行隔離澳叉,讓你更加心無旁騖的專注于你該專注的模塊。
關(guān)于AOP的相關(guān)概念這里不做多的講解沐悦,Google上都有成洗,我們直接以一個(gè)Demo來實(shí)現(xiàn)我們上述的需求。
項(xiàng)目完整代碼
https://github.com/KKaKa/AopDemo 歡迎Star
如何接入AspectJ
build.gradle
dependencies {
....
classpath 'org.aspectj:aspectjtools:1.8.9'
classpath 'org.aspectj:aspectjweaver:1.8.9'
}
build.gradle(app)
implementation 'org.aspectj:aspectjrt:1.8.9'
添加gradle腳本( 在build.gradle(app)中 )
final def log = project.logger
final def variants = project.android.applicationVariants
variants.all { variant ->
if (!variant.buildType.isDebuggable()) {
log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
return;
}
JavaCompile javaCompile = variant.javaCompile
javaCompile.doLast {
String[] args = ["-showWeaveInfo",
"-1.8",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
log.debug "ajc args: " + Arrays.toString(args)
MessageHandler handler = new MessageHandler(true);
new Main().run(args, handler);
for (IMessage message : handler.getMessages(null, true)) {
switch (message.getKind()) {
case IMessage.ABORT:
case IMessage.ERROR:
case IMessage.FAIL:
log.error message.message, message.thrown
break;
case IMessage.WARNING:
log.warn message.message, message.thrown
break;
case IMessage.INFO:
log.info message.message, message.thrown
break;
case IMessage.DEBUG:
log.debug message.message, message.thrown
break;
}
}
}
}
具體實(shí)現(xiàn)
大致分為三個(gè)步驟:
- 自定義切點(diǎn)
- 完成切面
- 對需要的方法添加注解
自定義切點(diǎn)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckLogin {
}
這里我們切點(diǎn)應(yīng)用于方法藏否,所以Target使用ElementType.METHOD瓶殃。
切點(diǎn)中可以添加參數(shù)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckLogin {
String param();
}
切面
@Aspect
public class CheckLoginAspectJ {
private static final String TAG = "CheckLoginAspectJ";
@Pointcut("execution(@com.laizexin.sdj.aopdemo.aspectj.CheckLogin * *(..))")
public void pointCut(){
}
@Before("pointCut()")
public void before(JoinPoint point){
Log.i(TAG,"CheckLoginAspectJ.before");
}
@Around("pointCut()")
public Object checkLogin(ProceedingJoinPoint joinPoint) throws Throwable{
...判斷是否登錄
return joinPoint.proceed();
}
@After("pointCut()")
public void after(JoinPoint point){
Log.i(TAG,"CheckLoginAspectJ.after");
}
@AfterThrowing(value = "pointcut()", throwing = "ex")
public void afterThrowing(Throwable ex) {
Log.i(TAG,"CheckLoginAspectJ.afterThrowing.ex = " + ex.getMessage());
}
}
@Pointcut("execution(@com.laizexin.sdj.aopdemo.aspectj.CheckLogin * *(..))")
這里的路徑要指向自己項(xiàng)目中的切點(diǎn)。
使用
@CheckLogin(param = "content")
private void toNextActivity(Context context,boolean isLogin) {
Log.i("CheckLoginAspectJ","toNextActivity");
}
如何獲取切點(diǎn)中的自定義的值
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
CheckLogin checkLogin = method.getAnnotation(CheckLogin.class);
String content = checkLogin.param();
如何獲取方法中的參數(shù)
for(Object obj : joinPoint.getArgs()){
//遍歷獲取值
....
}
反編譯結(jié)果
@CheckLogin(param="content")
private void toNextActivity(Context paramContext, boolean paramBoolean)
{
JoinPoint localJoinPoint = Factory.makeJP(ajc$tjp_0, this, this, paramContext, Conversions.booleanObject(paramBoolean));
try
{
CheckLoginAspectJ.aspectOf().before(localJoinPoint);
toNextActivity_aroundBody1$advice(this,paramContext, paramBoolean,localJoinPoint,CheckLoginAspectJ.aspectOf(), (ProceedingJoinPoint)localJoinPoint);
CheckLoginAspectJ.aspectOf().after(localJoinPoint);
return;
}
catch (java.lang.Throwable paramContext)
{
CheckLoginAspectJ.aspectOf().after(localJoinPoint);
}
throw paramContext;
}
這是我對AOP的一點(diǎn)理解副签,如有誤遥椿,歡迎指出基矮。