AOP系列:切面编程框架 : AspectJ

Android AOP方案(一)——AspectJ - 掘金AOP是一个概念,并没有设定具体语言的实现,它能克服那些只有单继承特性语言的缺点(如Java),AOP具体实现有很多种方式,AspectJ 只是其中一种。 AspectJ通过注解的形式来标注切入点、切入对象等,然后在代码编译期间将代码织入到java的字节码中。 该注解用来标注一…https://juejin.cn/post/6888548726424469511

Android切面编程主要是使用 AspectJ 只是其中的一种类型,事实上 AspectJ 是通过注解的形式来标注切入点,切入对象等,然后在代码编译期间将代码织入到 java字节码中, 从而实现切面编程意义。

AOP是一个概念,并没有设定具体语言的实现,它能克服那些只有单继承特性语言的缺点(如Java),AOP具体实现有很多种方式,AspectJ 只是其中一种。
AspectJ通过注解的形式来标注切入点、切入对象等,然后在代码编译期间将代码织入到java的字节码中。

Android使用 AspectJ 的步骤

1: AspectJ 注解

@Aspect 

该注解用来标注一个类,标明当前类是切面类,以便AspectJ能够识别。如:

@Aspect
public class FragmentAspectJInjector {

}

@Pointcut

标注一个方法,用来定义切点,参数为切点表达式。如定义一个切点是在Fragment的onResume生命周期方法执行的时候:

@Pointcut("execution(* android.app.Fragment+.onResume(..))")
public void fragmentOnResumePointcut() {
}

@Around,@Before,@After

标注一个方法,定义具体织入的代码,参数为切点表达式。 这里可以使用“&&、||、!”来组合不同的Pointcut定义。如我们在Fragment的onResume生命周期前打印下当前的Fragment对象:

@Around("fragmentOnResumePointcut()")
public void fragmentOnResume(final ProceedingJoinPoint joinPoint) throws Throwable {
    Object target = joinPoint.getTarget();
    Log.e(TAG, "fragmentOnResume: fragment = " + target);
    joinPoint.proceed();
}

AspectJ 注解还有很多,如@AfterReturning@AfterThrowing等,这里不再一一列举,大家有兴趣可以查看官方文档。上述这些注解基本已经可以满足我们的需求了。

第1步:新建一个Android project

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getFragmentManager().beginTransaction().replace(R.id.fragment, new BlankFragment()).commit();
    }
}

第2步:添加AspectJX依赖

根据AspectJX的github文档,我们在项目根目录的build.gradle里添加依赖

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.2.0-alpha07'
        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'
    }
}

在APP module中的build.gradle里应用插件

apply plugin: 'android-aspectjx'

第3步:添加切面类

@Aspect
public class FragmentAspectJInjector {
    private static final String TAG = "FragmentAspectJInjector";

    @Pointcut("execution(* android.app.Fragment+.onResume(..))")
    public void fragmentOnResumePointcut() {
    }

    @Around("fragmentOnResumePointcut()")
    public void fragmentOnResume(final ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget();
        Log.e(TAG, "fragmentOnResume: fragment = " + target);
        joinPoint.proceed();
    }

第4步:构建并运行APP

通过logcat窗口可以看到如下输出:可以看到我们的切点已经织入成功了。

E/FragmentAspectJInjector: fragmentOnResume: fragment = BlankFragment{8fafb1e #1 id=0x7f0800a4}\

AspectJ 缺点

  • 如果相应的class没有实现相应的切点方法将无法织入,如上文中的没有BlankFragment实现onResume方法的话,将无法织入代码。
  • 无法处理Lambda语法
  • 会有一系列兼容性问题,如R8、gradle版本不同等
  • 性能较差,APP项目比较大时编译时间明显加长。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值