前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android中Aop和Apt有什么区别?

Android中Aop和Apt有什么区别?

作者头像
乱码三千
发布2021-07-29 15:17:25
1.3K0
发布2021-07-29 15:17:25
举报
文章被收录于专栏:乱码三千乱码三千

什么是Aop?

AOP指的是:面向切面编程(Aspect-Oriented Programming)。如果说,OOP如果是把问题划分到单个模块的话,那么AOP就是把涉及到众多模块的某一类问题进行统一管理。

代表框架:

  • Hugo(Jake Wharton)
  • SSH
  • SpringMVC

Android 中应用

  • 日志
  • 持久化
  • 性能监控
  • 数据校验
  • 缓存
  • 按钮防抖
  • 其他更多

Android AOP就是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,提高开发效率

使用姿势

在Java中使用aop编程需要用到AspectJ切面框架,AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

1.在build.gradle文件中引入AspectJ

代码语言:javascript
复制
pply plugin: 'com.android.application'
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
android {
  ...
}

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;
            }
        }
    }
}


dependencies {
    ...
    implementation 'org.aspectj:aspectjrt:1.8.9'
}

2.创建注解类

代码语言:javascript
复制
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface SingleClick {
    long clickIntervals() default 800;
}

3.创建切面类

代码语言:javascript
复制
/**
 * 添加切面注解
 */
@Aspect
public class AopTest {
    private static final String TAG = "linhaojian";
    /**
     * 定义切入点(定义那些类或者方法需要改变)
     */
    @Pointcut("execution(*  com.lhj.test_apt..*ck(..))")
    public void pointcut1() {
    }
    /**
     * 使用注解方式,定义注解
     */
    @Pointcut("execution(@com.lhj.test_apt.DebugLog * *ck(..))")
    public void pointcut() {
    }
    /**
     * 前置通知,切点之前执行
     * @param point
     */
    @Before("pointcut()")
    public void logBefore(JoinPoint point){
        Log.e(TAG,"logBefore");
    }
    /**
     * 环绕通知,切点前后执行
     * @param joinPoint
     * @throws Throwable
     */
    @Around("pointcut()")
    public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Log.e(TAG,"logAround");
        // 1.执行切点函数(如果不调用该方法,切点函数不被执行)
        joinPoint.proceed();
    }
    /**
     * 后置通知,切点之后执行
     * @throws Throwable
     */
    @After("pointcut()")
    public void logAfter(JoinPoint point){
        Log.e(TAG,"logAfter");
    }
    /**
     * 返回通知,切点方法返回结果之后执行
     * @throws Throwable
     */
    @AfterReturning("pointcut()")
    public void logAfterReturning(JoinPoint point, Object returnValue){
        Log.e(TAG,"logAfterReturning ");
    }
    /**
     * 异常通知,切点抛出异常时执行
     * @throws Throwable
     */
    @AfterThrowing(value = "pointcut()",throwing = "ex")
    public void logAfterThrowing(Throwable ex){
        Log.e(TAG,"logAfterThrowing : "+ex.getMessage());
    }
}

4.使用

代码语言:javascript
复制
@SingleClick(clickIntervals = 2000)
    @Override
    public void onClick(View v) {
        Toast.makeText(this, "1", Toast.LENGTH_SHORT).show();
    }

难点: AspectJ语法比较多,但是掌握几个简单常用的,就能实现绝大多数切片,完全兼容Java(纯Java语言开发,然后使用AspectJ注解,简称@AspectJ。)

优点: AspectJ除了hook之外,AspectJ还可以为目标类添加变量,接口。另外,AspectJ也有抽象,继承等各种更高级的玩法。它能够在编译期间直接修改源代码生成class,强大的团战切入功能,指哪打哪,鞭辟入里。有了此神器,编程亦如庖丁解牛,游刃而有余。

什么是Apt?

APT(Annotation Processing Tool 的简称),可以在代码编译期解析注解,并且生成新的 Java 文件,减少手动的代码输入

代表框架:

  • DataBinding
  • Dagger2
  • ButterKnife
  • EventBus3
  • DBFlow
  • AndroidAnnotation
使用姿势

1,在android工程中,创建一个java的Module,写一个类继承AbstractProcessor

代码语言:javascript
复制
@AutoService(Processor.class) // javax.annotation.processing.IProcessor
@SupportedSourceVersion(SourceVersion.RELEASE_7) //java
@SupportedAnnotationTypes({ // 标注注解处理器支持的注解类型
    "com.annotation.SingleDelegate",
    "com.annotation.MultiDelegate"
})
public class AnnotationProcessor extends AbstractProcessor {
 
public static final String PACKAGE = "com.poet.delegate";
public static final String CLASS_DESC = "From poet compiler";
 
public Filer filer; //文件相关的辅助类
public Elements elements; //元素相关的辅助类
public Messager messager; //日志相关的辅助类
public Types types;
 
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
    filer = processingEnv.getFiler();
    elements = processingEnv.getElementUtils();
    messager = processingEnv.getMessager();
    types = processingEnv.getTypeUtils();
 
    new SingleDelegateProcessor().process(set, roundEnvironment, this);
    new MultiDelegateProcessor().process(set, roundEnvironment, this);
 
    return true;
}
}

2,重写AbstractProcessor类中的process方法,处理我们自定义的注解,生成代码:

代码语言:javascript
复制
public class SingleDelegateProcessor implements IProcessor {  
@Override
public void process(Set<? extends TypeElement> set, RoundEnvironment roundEnv,
                AnnotationProcessor abstractProcessor) {
// 查询注解是否存在
Set<? extends Element> elementSet =
        roundEnv.getElementsAnnotatedWith(SingleDelegate.class);
Set<TypeElement> typeElementSet = ElementFilter.typesIn(elementSet);
if (typeElementSet == null || typeElementSet.isEmpty()) {
    return;
}  
// 循环处理注解
for (TypeElement typeElement : typeElementSet) {
    if (!(typeElement.getKind() == ElementKind.INTERFACE)) { // 只处理接口类型
        continue;
    }
 
    // 处理 SingleDelegate,只处理 annotation.classNameImpl() 不为空的注解
    SingleDelegate annotation = typeElement.getAnnotation(SingleDelegate.class);
    if ("".equals(annotation.classNameImpl())) {
        continue;
    }
    Delegate delegate = annotation.delegate();
 
    // 添加构造器
    MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
            .addModifiers(Modifier.PUBLIC);
 
    // 创建类名相关 class builder
    TypeSpec.Builder builder =
            ProcessUtils.createTypeSpecBuilder(typeElement, annotation.classNameImpl());
 
    // 处理 delegate
    builder = ProcessUtils.processDelegate(typeElement, builder,
            constructorBuilder, delegate);
 
    // 检查是否继承其它接口
    builder = processSuperSingleDelegate(abstractProcessor, builder, constructorBuilder, typeElement);
 
    // 完成构造器
    builder.addMethod(constructorBuilder.build());
 
    // 创建 JavaFile
    JavaFile javaFile = JavaFile.builder(AnnotationProcessor.PACKAGE, builder.build()).build();
    try {
        javaFile.writeTo(abstractProcessor.filer);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
}

3,在项目Gradle中添加 annotationProcessor project 引用

代码语言:javascript
复制
compile project(':apt-delegate-annotation')  
annotationProcessor project(':apt-delegate-compiler')

4,如果有自定义注解的话,创建一个java的Module,专门放入自定义注解。项目与apt Module都需引用自定义注解Module

4-1,主工程:

代码语言:javascript
复制
compile project(':apt-delegate-annotation')  
annotationProcessor project(':apt-delegate-compiler')

4-2,apt Module:

代码语言:javascript
复制
compile project(':apt-delegate-annotation')  
compile 'com.google.auto.service:auto-service:1.0-rc2'
compile 'com.squareup:javapoet:1.4.0'  

5,生成的源代码在build/generated/source/apt下可以看到

难点

就apt本身来说没有任何难点可言,难点一在于设计模式和解耦思想的灵活应用,二在与代码生成的繁琐,你可以手动字符串拼接,当然有更高级的玩法用squareup的javapoet,用建造者的模式构建出任何你想要的源代码

优点

它的强大之处无需多言,看代表框架的源码,你可以学到很多新姿势。总的一句话:它可以做任何你不想做的繁杂的工作,它可以帮你写任何你不想重复代码。懒人福利,老司机必备神技,可以提高车速,让你以任何姿势漂移。它可以生成任何源代码供你在任何地方使用,就像剑客的剑,快疾如风,无所不及

Aop和Apt对比

如图所示:

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 乱码三千 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是Aop?
    • 使用姿势
    • 什么是Apt?
      • 使用姿势
      • Aop和Apt对比
      相关产品与服务
      应用性能监控
      应用性能监控(Application Performance Management,APM)是一款应用性能管理平台,基于实时多语言应用探针全量采集技术,为您提供分布式性能分析和故障自检能力。APM 协助您在复杂的业务系统里快速定位性能问题,降低 MTTR(平均故障恢复时间),实时了解并追踪应用性能,提升用户体验。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档