深入理解AOP(二) 之APT开发
2018-01-30 14:21
309 查看
对AOP 开发完全不了解的同学,请移步到 Android AOP 理解(一)
OK 今天我们来讲下AOP 中的APT 开发,通过上一遍我们已经知道目前市面上比较流行的APT 框架有
ButterKnife、Dagger2、DBFlow、AndroidAnnotation、EventBus
其中EventBus 3.x发布之后其通过注解预编译的方式解决了之前通过反射机制所引起的性能效率问题,其中注解预编译所采用的的就是
android-apt的方式,不过Apt工具的作者宣布了不再维护该工具了,因为Android Studio推出了官方插件,并且可以通过gradle来简
单的配置,它就是annotationProcessor,所以我们采用google官方推荐的方案来开发我们的APT项目。
在开始之前,我们要知道什么是APT:
APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。
Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。
有了这个想法之后,我们来写个简单的栗子,比如我们想让它自动生成如下代码:
首先,我们需要新建一个名称为annotation的Java Library(注意为什么这里创建Android Lib 是因为android默认不支持javax
包。这个包在我们complier中需要用到。所以这里我们暂且都采用创建 java Lib
),主要放置一些项目中需要使用到的Annotation和关联代码。这里简单自定义了一个注解:
配置gradle文件:
在这个module中我们新建一个TestProcessor 继承于AbstactProcessor(这个类具体干嘛的后面我们再说)
代码如下:
上面我们在TestProcessor中重写了AbstactProcessor中的4个方法,这4个方法的具体作用是什么?
1.init(ProcessingEnvironment
processingEnv)
所有的注解处理器类都必须有一个无参构造函数。然而,有一个特殊的方法init(),它会被注解处理工具调用,以ProcessingEnvironment作为参 数。ProcessingEnvironment
提供了一些实用的工具类Elements, Types和Filer。
2.process(Set<? extends TypeElement> annoations, RoundEnvironment env)
主要的逻辑处理都在这里,这个方法里面可以实现扫描,处理注解,生成
java 文件。使用RoundEnvironment 参数,可以查询被特定注解标注的元 素。
3.getSupportedAnnotationTypes()
在这个方法里面你必须指定哪些注解应该被注解处理器注册。注意,它的返回值是一个String集合,包含了你的注解处理器想要处理的注解类型的全称
4. getSupportedSourceVersion()
用来指定支持的java版本
在Java 7后多了 SupportedAnnotationTypes 和 SupportedSourceVersion 这个两个注解用来简化指定注解和java版本的操作:
也就是说可以改成这样:
gradle 配置如下:
然后在App中直接用注解就可以:
App gradle配置如下:
然后Rebuild下,就可以在App build/generated/source/apt/debug 目录中看到我们要生成的类了。
OK 今天我们来讲下AOP 中的APT 开发,通过上一遍我们已经知道目前市面上比较流行的APT 框架有
ButterKnife、Dagger2、DBFlow、AndroidAnnotation、EventBus
其中EventBus 3.x发布之后其通过注解预编译的方式解决了之前通过反射机制所引起的性能效率问题,其中注解预编译所采用的的就是
android-apt的方式,不过Apt工具的作者宣布了不再维护该工具了,因为Android Studio推出了官方插件,并且可以通过gradle来简
单的配置,它就是annotationProcessor,所以我们采用google官方推荐的方案来开发我们的APT项目。
在开始之前,我们要知道什么是APT:
APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。
Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。
有了这个想法之后,我们来写个简单的栗子,比如我们想让它自动生成如下代码:
package com.example.helloworld; import java.lang.String; import java.lang.System; public final class HelloWorld { public static void main(String[] args) { System.out.println("Hello, JavaPoet!"); } }
创建Annotation Module
首先,我们需要新建一个名称为annotation的Java Library(注意为什么这里创建Android Lib 是因为android默认不支持javax
包。这个包在我们complier中需要用到。所以这里我们暂且都采用创建 java Lib
),主要放置一些项目中需要使用到的Annotation和关联代码。这里简单自定义了一个注解:
package com.apt.andy.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by Administrator on 2018/1/24 0024. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface TestAnnotation { }
配置gradle文件:
apply plugin: 'java-library' dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) } sourceCompatibility = "1.7" targetCompatibility = "1.7"
创建Compiler Module
创建一个名为compiler的Java Library,注意,这个是我们的核心,我们自动生成的代码需要在这里编写在这个module中我们新建一个TestProcessor 继承于AbstactProcessor(这个类具体干嘛的后面我们再说)
代码如下:
@AutoService(Processor.class) public class TestProcessor extends AbstractProcessor { @Override public Set<String> getSupportedAnnotationTypes() { return Collections.singleton(TestAnnotation.class.getCanonicalName()); } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.RELEASE_7; } @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); } @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args") .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") .build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(main) .build(); JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld) .build(); try { javaFile.writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } return true; } }
上面我们在TestProcessor中重写了AbstactProcessor中的4个方法,这4个方法的具体作用是什么?
1.init(ProcessingEnvironment
processingEnv)
所有的注解处理器类都必须有一个无参构造函数。然而,有一个特殊的方法init(),它会被注解处理工具调用,以ProcessingEnvironment作为参 数。ProcessingEnvironment
提供了一些实用的工具类Elements, Types和Filer。
2.process(Set<? extends TypeElement> annoations, RoundEnvironment env)
主要的逻辑处理都在这里,这个方法里面可以实现扫描,处理注解,生成
java 文件。使用RoundEnvironment 参数,可以查询被特定注解标注的元 素。
3.getSupportedAnnotationTypes()
在这个方法里面你必须指定哪些注解应该被注解处理器注册。注意,它的返回值是一个String集合,包含了你的注解处理器想要处理的注解类型的全称
4. getSupportedSourceVersion()
用来指定支持的java版本
在Java 7后多了 SupportedAnnotationTypes 和 SupportedSourceVersion 这个两个注解用来简化指定注解和java版本的操作:
也就是说可以改成这样:
@SupportedAnnotationTypes({"com.apt.andy.annotation.TestAnnotation"}) @SupportedSourceVersion(SourceVersion.RELEASE_7) @AutoService(Processor.class) public class TestProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); } @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args") .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") .build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(main) .build(); JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld) .build(); try { javaFile.writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } return true; } }其中SupportedAnnotationTypes 如果支持多个注解,中间用逗号隔开
gradle 配置如下:
apply plugin: 'java-library' dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) compile 'com.squareup:javapoet:1.7.0' compile 'com.google.auto.service:auto-service:1.0-rc2' compile project(':annotation') } sourceCompatibility = "1.7" targetCompatibility = "1.7"
然后在App中直接用注解就可以:
package com.apt.andy.myfirstaptdemo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import com.apt.andy.annotation.TestAnnotation; @TestAnnotation public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
App gradle配置如下:
apply plugin: 'com.android.application' android { compileSdkVersion 26 defaultConfig { applicationId "com.apt.andy.myfirstaptdemo" minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.0.2' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' compile project(':annotation') annotationProcessor project(':compile') }
然后Rebuild下,就可以在App build/generated/source/apt/debug 目录中看到我们要生成的类了。
相关文章推荐
- 移动前端开发之viewport的深入理解
- magento 开发 -- 深入理解Magento第四章 – 模型和ORM基础
- iOS8开发~UI布局(三)深入理解autolayout
- 移动前端开发之viewport的深入理解
- 深入理解jQuery插件开发【转】
- 深入理解jQuery插件开发
- rcp(插件开发)深入理解菜单(Menu)功能及其扩展点
- iOS开发CoreGraphics核心图形框架之二——深入理解图形上下文
- magento 开发 -- 深入理解Magento第七章 – 自定义Magento系统配置
- 安卓开发21:深入理解Handler
- 深入理解Spring的两大特征(IOC和AOP)
- 深入理解nginx chap3 开发一个简单的HTTP模块
- 深入理解iOS开发中的BitCode功能
- 软件开发中面向对象的深入理解
- Android开发之深入理解Android 7.0系统权限更改相关文档
- 深入Android应用开发-透彻理解Permission
- iOS开发之深入理解GCD
- 深入理解AOP
- 深入理解Spring AOP之二代理对象生成
- iOS8开发~UI布局(三)深入理解autolayout