手写简化EventBus之注解处理器方式,理解框架核心原理

前言

自前一篇文章:手写简化EventBus,理解框架核心原理(反射实现方式)写完后,一直在研究注解处理器实现方式,中间又有其他事情耽搁了,所以到今天才补上这篇文章。
此篇文章是在上篇反射方式实现的源码的基础上进行更改实现的,所以如果还没看上篇文章的可以先浏览下,能够更快的了解脉络和源码结构,能够更快的进入主题,更快理解。

注解处理器(APT)

顾名思义,APT就是注解处理器,其是Annotation Processing Tool的简称。它是javac的一个工具,用来在编译期扫描和处理注解,通过注解来生成文件(通常是java文件)。即以注解作为桥梁,通过预先规定好的代码生成规则来自动生成 Java 文件。这些生成的java文件会同其手动编写的java代码一样会被javac编译。
简单的流程框图如下:即原来需要在程序运行时获取的方法集合,现在可以在编译时注解生成的新类A中的某个方法获取了。此种方式可以减轻初始化时反射带来的性能损耗,当然此损耗是在项目较大,注册较多时比较明显。
在这里插入图片描述虽然流程图上画的是调用注解处理器,但是Android工程编译的时候JVM怎么找到我们自定义的注解处理器?这个时候就要用到Java SPI机制(这里只引出概念,有需要的可以一起查阅学习,深入研究原理,这里只当做黑箱,使用这个能力)。就是在annotationprocess模块的resources目录下新建META-INF/services,然后新建File,名称javax.annotation.processing.Processor,文件内容就是我们自定义注解处理器的全限定名com.example.AnnotationProcessor,谷歌官方也出品了一个开源库Auto-Service,通过注解@AutoService(Processor.class)可以省略上面配置的步骤。AutoService会自动在META-INF文件夹下生成Processor配置信息文件,该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
其中AbstractProcessor 的主要方法如下:

public abstract class AbstractProcessor implements Processor {
   
//获取要处理的注解的类型(本例中是@Subscribe)可通过注解方式赋值
public Set<String> getSupportedAnnotationTypes() {
   
	SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class);
……
}
// 获取java需要支持的版本,可注解方式赋值
public SourceVersion getSupportedSourceVersion() {
   
        SupportedSourceVersion ssv = this.getClass().getAnnotation(SupportedSourceVersion.class);
        ……
}
// 初始化注解处理器
public synchronized void init(ProcessingEnvironment processingEnv) {
   
     ……
}
// 要实现的process方法,在实现类中此方法主要是生成新的类文件。
public abstract boolean process(Set<? extends TypeElement> annotations,RoundEnvironment roundEnv);
}

实际上,生成这个类文件A也有两种方式,一个就是用注解处理器自带的processingEnv里的生成文件的方法。另一种即是使用框架javapoet。通过javapoet这个名字翻译,java 诗人,你能想象写代码会有多优雅。
其中processingEnv自带的方式,也是EventBus3.0源码目前使用的方式生成代码示例为:

BufferedWriter writer = null;
        try {
   
            JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index);
            int period = index.lastIndexOf('.');
            String myPackage = period > 0 ? index.substring(0, period) : null;
            String clazz = index.substring(period + 1);
            writer = new BufferedWriter(sourceFile.openWriter());
            if (myPackage != null) {
   
                writer.write("package " + myPackage + ";\n\n");
            }
            writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n");
            writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n");
            writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n");
            writer.write("import java.util.HashMap;\n");
            writer.write("import java.util.Map;\n\n");
            writer.write("/** This class is generated by EventBus, do not edit. */\n");
            writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n");
            writer.write("    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;\n\n");
            writer.write("    static {\n");
            writer.write("        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();\n\n");
            writeIndexLines(writer, myPackage)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值