赞
踩
本文来自享学derry老师的课堂分享
APT初窥
APT(Annotation Processing Tool)
是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,根据注解自动生成代码,如果想要自定义的注解处理器能够正常运行,必须要通过APT工具来进行处理。也可以这样理解,只有通过声明APT工具后,程序在编译期间自定义注解解释器才能执行。
通俗理解:根据规则,帮我们生成代码、生成类文件
PackageElement:
表示一个包程序元素。提供对有关包及其成员的信息的访问
ExecutableElement:
表示某个类或接口的方法、构造方法或初始化程序(静态或实例)
TypeElement:
表示一个类或接口程序元素。提供对有关类型及其成员的信息的访问。
VariableElement:
表示一个字段、enum 常量、方法或构造方法参数、局部变量或异常参数
问:
1、APT全称:annotation process tool是一种处理注释的工具,它对源代码文件进行检测查找出其中的Annotation,使用Annotation进行额外的处理
APT 编译的时候 ---> 处理注解
APT 传统方式 ---> 生成 java文件
APT JavaPoet方式 --> 生成Java文件
2、传统方式 那些 开源项目有用到?
答:看看EventBus源码就知道了
https://www.jianshu.com/p/f057c460c77e
https://www.jianshu.com/p/633348569198
传统方式:优点(编程的流程写下去) 缺点(没有oop思想加入进来)
3、JavaPoet是什么?
JavaPoet是square推出的开源java代码生成框架,提供Java Api生成.java源文件 这个框架功能非常实用,也是我们习惯的Java面向对象OOP语法
可以很方便的使用它根据注解生成对应代码
通过这种自动化生成代码的方式,
可以让我们用更加简洁优雅的方式要替代繁琐冗杂的重复工作
项目主页及源码:https://github.com/square/javapoet
1、属性
2、高级用法
JavaPoet到底是什么?
答:oop思想方式:优点(加入oop思想) 缺点(不习惯,倒序)
3、组件化项目部署、ARouter原理
1、建立相应的项目结构
2、导入需要的包
compiler下的gradle,compiler是apt的注解包
- apply plugin: 'java-library'
-
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
-
- // 背后的服务 能够监听 你是否在编译中.....
- // AS3.4.1 + Gradle 5.1.1 + auto-service:1.0-rc4
- compileOnly'com.google.auto.service:auto-service:1.0-rc4'
- annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'
-
- // 帮助我们通过类调用的形式来生成Java代码 [JavaPoet]
- implementation "com.squareup:javapoet:1.9.0"
-
- // 依赖注解
- implementation project(":arouter-annotations")
- }
arouter-annotation中的自定义的注解处理器
- @Target(TYPE) // 类上
- @Retention(CLASS) // 编译期 XUtil==运行期
- public @interface ARouter {
-
- String path();
-
- String group() default "";
-
- }
app工程下gradle,添加两个注解包的依赖
- // 依赖注解
- implementation project(":arouter-annotations")
-
- // 依赖注解处理器 注解处理器才能工作
- annotationProcessor project(":compiler")
下面看一下注解处理器怎么处理注解,在编译时期识别注解并转成java代码的
在compiler下创建ARouterProcessor,这里面就是手动获取了被注解的类的信息,并且一一对应生成了对应的java文件
- @AutoService(Processor.class) // 启用服务
- @SupportedAnnotationTypes({"com.derry.arouter_annotations.ARouter"}) // 注解
- @SupportedSourceVersion(SourceVersion.RELEASE_7) // 环境的版本
-
-
- // 接收 安卓工程传递过来的参数
- @SupportedOptions("student")
-
- public class ARouterProcessor extends AbstractProcessor {
-
- // 操作Element的工具类(类,函数,属性,其实都是Element)
- private Elements elementTool;
-
- // type(类信息)的工具类,包含用于操作TypeMirror的工具方法
- private Types typeTool;
-
- // Message用来打印 日志相关信息
- private Messager messager;
-
- // 文件生成器, 类 资源 等,就是最终要生成的文件 是需要Filer来完成的
- private Filer filer;
-
- @Override
- public synchronized void init(ProcessingEnvironment processingEnvironment) {
- super.init(processingEnvironment);
-
- elementTool = processingEnvironment.getElementUtils();
- messager = processingEnvironment.getMessager();
- filer = processingEnvironment.getFiler();
-
- String value = processingEnvironment.getOptions().get("student");
-
- // 如果我想在注解处理器里面抛出异常 可以使用Diagnostic.Kind.ERROR
- messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>>>>>>>>>>>>>>>>>"+value);
- }
-
- // 服务:在编译的时候干活
- // 坑:如果没有在任何地方使用,次函数是不会工作的
- @Override
- public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
-
- messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>> Derry run...");
-
- if (set.isEmpty()) {
- return false; // 不干活
- }
-
- // 循环?
- // 获取被 ARouter注解的 "类节点信息"
- Set<? extends Element> elements =
- roundEnvironment.getElementsAnnotatedWith(ARouter.class);
- for (Element element : elements) { // for 3 // 1 element == MainActivity 2
- element == MainActivity2
- // 注释部分是基本使用,写死了各种类
- /**
-
- 模块一
- package com.example.helloworld;
- public final class HelloWorld {
- public static void main(String[] args) {
- System.out.println("Hello, JavaPoet!");
- }
- }
- */
- // Java 万物皆对象
- // C 万物皆指针
- /*// 1.方法
- MethodSpec mainMethod = MethodSpec.methodBuilder("main")
- .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
- .returns(void.class)
- .addParameter(String[].class, "args")
- // 增加main方法里面的内容
- .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
- .build();
- // 2.类
- TypeSpec testClass = TypeSpec.classBuilder("DerryTest")
- .addMethod(mainMethod)
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .build();
- // 3.包
- JavaFile packagef = JavaFile.builder("com.xiangxue.test", testClass).build();
- // 生成文件
- try {
- packagef.writeTo(filer);
- } catch (IOException e) {
- e.printStackTrace();
- messager.printMessage(Diagnostic.Kind.NOTE, "生成Test文件时失败,异常:" + e.getMessage());
- }*/
- //获取包名方法示例
- // 包信息
- String packageName = elementTool.getPackageOf(element).getQualifiedName().toString();
-
- // 获取简单类名,例如:MainActivity MainActivity2 MainActivity3
- String className = element.getSimpleName().toString();
- messager.printMessage(Diagnostic.Kind.NOTE, "被@ARetuer注解的类有:" + className);
-
- // String className = element.getSimpleName().toString();
-
- // 目标:要生成的文件名称 MainActivity$$$$$$$$$ARouter
- String finalClassName = className + "$$$$$$$$$ARouter";
-
- /**
- 模板:
- public class MainActivity3$$$$$$$$$ARouter {
- public static Class findTargetClass(String path) {
- return path.equals("/app/MainActivity3") ? MainActivity3.class : null;
- }
- }
- */
-
- ARouter aRouter = element.getAnnotation(ARouter.class);
- //这下面开始是动态使用
- // 1.方法
- MethodSpec findTargetClass = MethodSpec.methodBuilder("findTargetClass")
- .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
- .returns(Class.class)
- .addParameter(String.class, "path")
- // 方法里面的内容 return path.equals("/app/MainActivity3") ? MainActivity3.class : null;
-
- // 需要JavaPoet包装转型
- .addStatement("return path.equals($S) ? $T.class : null",
- aRouter.path(),
- ClassName.get((TypeElement) element))
- .build();
-
- // 2.类
- TypeSpec myClass = TypeSpec.classBuilder(finalClassName)
- .addMethod(findTargetClass)
- .addModifiers(Modifier.PUBLIC)
- .build();
-
- // 3.包
- JavaFile packagef = JavaFile.builder(packageName, myClass).build();
-
- // 开始生成
- try {
- packagef.writeTo(filer);
- } catch (IOException e) {
- e.printStackTrace();
- messager.printMessage(Diagnostic.Kind.NOTE, "生成" + finalClassName + "文件时失败,异常:" + e.getMessage());
- }
- }
-
- return true; // false不干活了 true干完了
- }
- }
来看一下调用
- @ARouter(path = "/app/MainActivity3")
- public class MainActivity3 extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
- }
看一下build的文件,名字,方法都是我们框架里自定义的
- public class MainActivity3$$$$$$$$$ARouter {
- public static Class findTargetClass(String path) {
- return path.equals("/app/MainActivity3") ? MainActivity3.class : null;
- }
- }
可以看到我们可以通过编译成的代码来获取其他未实例化的方法,从mainactivity获取类mainactivity3
- @ARouter(path = "/app/MainActivity")
- public class MainActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
-
- public void startMainActivity3(View view) {
- Class startClass = MainActivity3$$$$$$$$$ARouter.findTargetClass("/app/MainActivity3");
- }
- }
这就是apt以及为了实现apt技术的手段:javapoet的使用及介绍。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。