Android-注解处理器

Android-Java注解处理器

基本概念

注解处理器(Annotation Processor)是javac的一个工具。它用来在编译时扫描和处理注解(Annotation)。你能够对自己定义注解,并注冊对应的注解处理器。到这里,我如果你已经知道什么是注解,而且知道怎么申明的一个注解。

假设你不熟悉注解,你能够在这官方文档中得到很多其它信息。

注解处理器在Java 5開始就有了,可是从Java 6(2006年12月公布)開始才有可用的API。

过了一些时间,Java世界才意识到注解处理器的强大作用,所以它到近期几年才流行起来。

一个注解的注解处理器,以Java代码(或者编译过的字节码)作为输入。生成文件(一般是.java文件)作为输出。这详细的含义什么呢?你能够生成Java代码。这些生成的Java代码是在生成的.java文件里,所以你不能改动已经存在的Java类。比如向已有的类中加入方法。这些生成的Java文件,会同其它普通的手动编写的Java源码一样被javac编译。

使用注解处理器

以下来讲述怎么在Android Studio中使用注解处理器,

在这里就须要介绍一个gradle插件android-apt了,

官方地址:
https://bitbucket.org/hvisser/android-apt

Android Studio原本是不支持注解处理器的, 可是用这个插件后, 我们就能够使用注解处理器了, 这个插件能够自己主动的帮你为生成的代码创建文件夹, 让生成的代码编译到APK里面去, 并且它还能够让终于编译出来的APK里面不包括注解处理器本身的代码, 由于这部分代码仅仅是编译的时候须要用来生成代码, 终于执行的时候是不须要的。

使用这个插件非常easy, 首先在你项目顶层的build.gradle文件里加入依赖项, 例如以下:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath ‘com.android.tools.build:gradle:1.5.0‘
        classpath ‘com.neenbedankt.gradle.plugins:android-apt:1.8‘
    }
}

然后在app的build.gradle里面加入插件的引用以及须要依赖哪些库, 例如以下:

apply plugin: ‘com.android.application‘
apply plugin: ‘com.neenbedankt.android-apt‘
...
dependencies {
    compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
    testCompile ‘junit:junit:4.12‘
    compile ‘com.android.support:appcompat-v7:22.2.1‘
    compile ‘la.dahuo:command:1.0.0‘
    apt ‘la.dahuo:command-codegen:1.0.0‘
}

注意上面的apt ‘la.dahuo:command-codegen:1.0.0’, 这里表示引用一个注解处理器的库, 这个库的代码终于不会进入编译出来的APK里面。

使用注解

以下就来介绍怎么使用注解生成代码, 上面出现的库la.dahuo:command,

la.dahuo:command-codegen就是我依据命令设计模式(Command Design Pattern)写的一个注解库, 它用来让我们方便的生成代码, 看下使用方法:

定义Command

@CommandDef("commandName")public class MyCommand extends Command {        @Param    String paramStr;        @Param("paramIntName")    int paramInt;        @Override
    public void execute() {        // do something with params
    }
}

上面的代码通过@CommandDef(“commandName”)来标注MyCommand是一个Command类, 它相应的名字为commandName. 然后通过标注@Param来定义了两个參数, @Param不填值的话表示參数名和属性名一样, 也能够通过填入一个值来指定參数名

使用Command

Map<String, Object> params = new HashMap<>();
params.put("paramStr", "string");
params.put("paramIntName", 1);
Command.parse("commandName", params).execute();

分析

看完上面的使用方法, 你可能会认为就这么多代码就能够跑了吗?

不须要再加入什么代码了?

我的答案是: 确实能够跑, 不须要加入其它代码了。

有木有认为用起来非常方便?

我们以下来分析下这是怎么做到的。

首先标注处理器会依据@Param来获取Command的结构信息, 然后用来生成CommandFactory, 生成的代码在build/generated/source/apt以下, 生成的CommandFactory例如以下:

public class MyCommandFactory implements CommandFactory {    public Command newCommand(Map<String, Object> params) {
        MyCommand command = new MyCommand();
        command.paramStr = TypeConverter.toString(params.get("paramStr"));
        command.paramInt = TypeConverter.toInt(params.get("paramIntName"));        return command;
    }
}

有了CommandFactory, 我们就能够通过Mapparams来构造Command了.

那Command是怎么自己主动注冊的呢? 那我们就要看另外一个生成的类了.

public class CommandRegisters {    public static void register(Map<String, CommandFactory> map) {        map.put("myCommand", new MyCommandFactory());
    }
}

它依据标注@CommandDef来获取了全部Command类的信息, 然后完毕全部Command的注冊.

有了上面自己主动生成的代码, 那么解析Command就非常easy了. 代码例如以下:

public static Command parse(String action, Map<String, Object> params) {
    CommandFactory factory = CommandRepository.getInstance().getFactory(action);    if (factory != null) {        return factory.newCommand(params);
    }    return EmptyCommand.INSTANCE;
}

CommandRepository类通过反射的方式调用CommandRegisters类的register方法来完毕全部Command的注冊. 这是我这个注解库唯一的一处使用反射的地方, Command的创建都通过CommandFactory来完毕, 性能非常高, 比那些通过大量反射来实现对象映射的库性能好非常多(比方GSON, 能够实现json转object), 并且也不须要依赖非常多代码, 依赖一个非常小的库

la.dahuo:command就够了, 才5K.

怎么创建注解处理器

注解处理器最核心的就是要有一个Processor, 它继承自AbstractProcessor,它长成这个样子:

package com.example;

public class MyProcessor extends AbstractProcessor {        @Override
    public synchronized void init(ProcessingEnvironment env){ }

   @Override
    public boolean process(Set<?

extends TypeElement> annoations, RoundEnvironment env) { }

   @Override
    public Set<String> getSupportedAnnotationTypes() { }        @Override
    public SourceVersion getSupportedSourceVersion() { }
}
  • init(ProcessingEnvironment env):每一个注解处理器都必须有个空的构造方法。

    只是,有一个特殊的init方法,它会被注解处理器工具传入一个ProcessingEnvironment作为參数来调用。

    ProcessingEnvironment提供了一些实用的工具类,如Elements。Types和Filter。

    我们后面会用到它们。

  • process(Set<?

    extends TypeElement> annotations, RoundEnvironment env):这种方法能够看做每一个处理器的main方法。你要在这里写下你的扫描。推断和处理注解的代码。并生成java文件。

    通过传入的RoundEnvironment參数,你能够查询被某个特定注解注解的元素,我们稍后会看到。

  • getSupportedAnnotationTypes( ):这里你须要说明这个处理器须要针对哪些注解来注冊。注意返回类型是一个字符串的Set,包括了你要用这个处理器处理的注解类型的全名。
  • getSupportedSourceVersion( ):用于指定你使用的java版本号。通常你会返回SourceVersion.latestSupported( )。

接下来你须要知道的一件事就是注解处理器在它自己的JVM中执行。是的,你没看错。javac启动一个完整的Java虚拟机来给注解处理器执行。这对你意味着什么?你能够使用你在不论什么其它java应用中使用的东西,比方谷歌的guava!假设你愿意。你还能够使用依赖注入工具,如dagger或不论什么你想要使用的库。只是不要忘了。虽然这仅仅是个小的处理器,你依旧须要考虑高效的算法和设计模式,就像是你会为不论什么其它Java应用所做的那样。

注冊你的处理器

你或许会问自己:”我该如何把我的处理器注冊到javac?”。

你须要提供一个.jar文件。就像其它的jar文件一样,你要把编译后的处理器打包到那个文件。

并且你还须要把一个特别的放在META-INF/services下的叫做javax.annotation.processing.Processor的文件打包进你的.jar文件。

所以你的.jar文件内容看起来会像这个样子:

MyProcessor.jar
    - com
        - example
            - MyProcessor.class
    - META-INF
        - services
            - javax.annotation.processing.Processor

java.annotation.processing.Processor文件(打包到MyProcessor.jar中)的内容是用换行符隔开的处理器完整类名:

com.example.MyProcessor
com.foo.OtherProcessor
net.blabla.SpecialProcessor

这样, 一个注解处理器的框架就好了, 完毕代码后编译成jar文件, 然后像開始介绍的那样加入依赖就好了.

gitbub原地址:https://github.com/derron/command-lib#rd

时间: 2024-10-10 20:26:21

Android-注解处理器的相关文章

一小时搞明白注解处理器(Annotation Processor Tool)

Java中的注解是个很神奇的东西,还不了解的可以看下一小时搞明白自定义注解(Annotation).现在很多Android的库都用使用注解实现的,比如ButterKnife,我们不防也来学习一下,学完注解处理器,我们尝试写一个简单的类似ButterKnife的东西来绑定控件. 什么是注解处理器? 注解处理器是(Annotation Processor)是javac的一个工具,用来在编译时扫描和编译和处理注解(Annotation).你可以自己定义注解和注解处理器去搞一些事情.一个注解处理器它以J

Android注解使用之通过annotationProcessor注解生成代码实现自己的ButterKnife框架

前言: Annotation注解在Android的开发中的使用越来越普遍,例如EventBus.ButterKnife.Dagger2等,之前使用注解的时候需要利用反射机制势必影响到运行效率及性能,直到后来android-apt的出现通过注解根据反射机制动态编译生成代码的方式来解决在运行时不再使用发射机制,不过随着android-apt的退出不再维护,我们今天利用Android studio的官方插件annotationProcessor来实现一下自己的ButterKnife UI注解框架. 需

Android 注解框架对比

Java的注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,标记可以加在包,类,属性,方法,本地变量上.然后你可以写一个注解处理器去解析处理这些注解(人称编译时注解),也可以在程序运行时利用反射得到注解做出相应的处理(人称运行时注解).       开发Android程序时,没完没了的findViewById, setOnClickListener等等方法,已经让大多数开发者头疼不已.好在市面上有所谓的注解框架可以帮助开发者简化一些过程.比较流行的有butte

android注解处理技术APT

APT(Annotation Processing Tool)是java的注解处理技术,它对源代码文件进行检测找出其中的Annotation,根据注解和注解处理器和相应的apt自动生成代码. Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定). 1.什么是APT? android-apt和annotationProcessor功能是一样的,都是apt的实现,前者比较早,后

Java注解(2)-注解处理器(运行时|RetentionPolicy.RUNTIME)

如果没有用来读取注解的工具,那注解将基本没有任何作用,它也不会比注释更有用.读取注解的工具叫作注解处理器.Java提供了两种方式来处理注解:第一种是利用运行时反射机制:另一种是使用Java提供的API来处理编译期的注解. 反射机制方式的注解处理器 仅当定义的注解的@Retention为RUNTIME时,才能够通过运行时的反射机制来处理注解.下面结合例子来说明这种方式的处理方法. Java中的反射API(如java.lang.Class.java.lang.reflect.Field等)都实现了接

Java注解(3)-注解处理器(编译期|RetentionPolicy.SOURCE)

注解的处理除了可以在运行时通过反射机制处理外,还可以在编译期进行处理.在编译期处理注解时,会处理到不再产生新的源文件为止,之后再对所有源文件进行编译. Java5中提供了apt工具来进行编译期的注解处理.apt是命令行工具,与之配套的是一套描述"程序在编译时刻的静态结构"的API:Mirror API(com.sun.mirror.*).通过Mirror API可以获取到被注解的Java类型元素的信息,从而提供自定义的处理逻辑.具体的处理工具交给apt来处理.编写注解处理器的核心是两个

深入理解Java:注解(Annotation)--注解处理器

深入理解Java:注解(Annotation)--注解处理器 如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了.使用注解的过程中,很重要的一部分就是创建于使用注解处理器.Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处理器. 注解处理器类库(java.lang.reflect.AnnotatedElement): Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口.除此之外,Java在java.l

springmvc03 非注解和注解处理器映射器和适配器

1其它非注解处理器映射器和适配器 1.1BeanNameUrlHandlerMapping(映射器) 根据请求url(XXXX.action)匹配spring容器bean的 name 找到对应的bean(程序编写的Handler) 1.2SimpleUrlHandlerMapping(映射器) <!--简单url映射, 集中配置bean的id对应 的url --> <bean class="org.springframework.web.servlet.handler.Simp

Java注解处理器

这几天看公司一个中间件对异步的支持的新特性中,它使用注解处理器来自动生成异步接口.就看了下如何使用注解及编译期注解处理器,一下是些学习笔记吧! 此处说的Java注解及注解处理器,不是运行期注解及使用Class对象和反射来处理的处理器!而是编译期处理的源文件注解(RetentionPolicy.SOURCE);其注解处理器(Annotation Processor)是javac的一个工具,它用来在编译时扫描和处理注解(Annotation).你可以对自定义注解,并注册相应的注解处理器. 用途 编译

java 命名代码检查-注解处理器

命名代码检查 根据 <Java 语言规范( 第 3 版 ) > 中第6.8节的要求, Java 程序命名应当符合下列格式的书写规范: 类 ( 或接口 ) : 符合驼式命名法, 首字母大写. 方法 : 符合驼式命名法,首字母小写 字段 : 类或实例变量 : 符合驼式命名法 , 首字母小写 常量 : 要求全部有大写字母或下划线构成, 并且第一个字符不能是下划线. 要通过注解处理器的API 实现一个编译器插件 , 首先需要了解这组 API 的基本知识.我们实现注解处理器的代码需要继承抽象类 java