zoukankan      html  css  js  c++  java
  • Android框架式编程之JavaPoet框架

    一、JavaPoet 介绍

    JavaPoet是Square推出的开源Java代码生成框架,提供Java Api生成.java源文件。这个框架功能非常有用,我们可以很方便的使用它根据注解、数据库模式、协议格式等来对应生成代码。通过这种自动化生成代码的方式,可以让我们用更加简洁优雅的方式要替代繁琐冗杂的重复工作。

    代码生成技术相当于元编程,可用于编译期根据注解等元数据动态生成Java类。广泛使用的Dagger,ButterKnife框架就是利用JavaPoet对注入注解生成所需类。

    项目主页:https://github.com/square/javapoet

    二、JavaPoet 关键类说明

    JavaPoet中,有以下几个关键类:

    JavaFile:用于构造输出包含一个顶级类的Java文件,是对.java文件的抽象。

    TypeSpec:TypeSpec是类/接口/枚举的抽象。

    MethodSpec:MethodSpec是方法/构造函数的抽象。

    FieldSpec:FieldSpec是成员变量/字段的抽象。

    ParameterSpec:ParameterSpec用于创建参数。

    AnnotationSpec:AnnotationSpec用于创建注解。

    在JavaPoet中,所有Java文件的抽象元素都定义了emit方法,如TypeSepc,ParameterSepc等,emit方法传入CodeWriter对象输出字符串。上层元素调用下层元素的emit方法,如JavaFile的emit方法调用TypeSpec的emit方法,从而实现整个Java文件字符串的生成。

    三、JavaPoet 的使用方式

    首先需要引入库:

    compile 'com.squareup:javapoet:1.13.0'

    一般情况下,还需要配合注解解释器来使用才行,一般我们常用的或注解解释器为 AutoServicegradle-incap-helper

    这里我们以JavaPoet + AutoService来举例,讲解一下如何使用JavaPoet自动生成代码。

    1. 配置 AutoService 的库

    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
    compileOnly 'com.google.auto.service:auto-service:1.0-rc4'

    2. 编写注解解释器代码

    @AutoService(Processor.class)
    @SupportedAnnotationTypes(Constant.ANY_TYPE)
    public class CustomProcessor extends AbstractProcessor {
    
        private Filer filer;   // 文件生成器
    
        /**
         *  初始化方法
         */
        @Override
        public synchronized void init(ProcessingEnvironment processingEnvironment) {
            super.init(processingEnvironment);
            filer = processingEnvironment.getFiler();
        }
    
        /**
         * 此函数用于正式处理注解
         */
        @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(filer);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }
    
        @Override
        public SourceVersion getSupportedSourceVersion() {
            return SourceVersion.RELEASE_7;
        }
    
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            return super.getSupportedAnnotationTypes();
        }
    }

    3. Build项目

    完成Build后,就去Build 文件下查找生成的代码,然后我们就看到:

    生成的代码内容为我们期望的内容:

    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!");
      }
    }

    至此,JavaPoet 的简单使用方式,我们就讲完了。感兴趣的可以进一步研读其代码进行进一步的理解。

    四、JavaPoet 框架使用场景

    早期的EventBus和ButterKnife都是通过注解并收集缓存相关的类&方法,然后使用时通过反射的方式进行调用,这样实现虽然功能使用方面没问题,但是在性能上会因为反射机制为核心导致性能瓶颈。

    在后续的EventBus和ButterKnife的大改版中,对此都进行了优化,通过查看EventBus和ButterKnife项目的源码,我们可以发现它们不约而同地都使用到了JavaPoet来进行代码的自动生成,进而通过编译期代码自动生成的方式避免在运行时的反射调用,进而优化性能体验。目前两者对应的注解解释器都是 gradle-incap-helper

    在开发的时候,当我们需要实现一些对性能要求较高的框架或逻辑的时候,动态生成Java代码技术是替代运行时反射技术的一个很好的选项。

    五、知识延申 - 注解处理器

    注解处理器(Annotation Processor)是javac的一个工具,它用来在编译时扫描和处理注解(Annotation)。你可以自定义注解,并注册相应的注解处理器(自定义的注解处理器需继承自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()方法,它会被注解处理工具调用,并输入ProcessingEnviroment参数。ProcessingEnviroment提供很多有用的工具类如Elements, Types和Filer等。
    • process(Set< ? extends TypeElement> annotations, RoundEnvironment env): 这相当于每个处理器的主函数main()。你在这里写你的扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让你查询出包含特定注解的被注解元素。
    • getSupportedAnnotationTypes(): 这里你必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。
    • getSupportedSourceVersion(): 用来指定你使用的Java版本。通常这里返回SourceVersion.latestSupported()。

    需要注意的是:注解处理器是运行在独立的虚拟机JVM中,javac启动一个完整Java虚拟机来运行注解处理器。

  • 相关阅读:
    焦虑:都说程序员是青春饭,那么程序员老了何去何从呢?
    数据库查询语句优化,mysql优化,join语句优化附带YYC松鼠短视频系统详细demo效果
    IT行业:为什么大部分人都不认可php语言呢?
    拇指赚点赞无加密源码发布分享仅供学习
    区块鼠区块养殖系统源码无加密源码发布分享仅供学习
    3月1日晚突遭大量攻击,网站/APP突然遭遇黑客攻击时该如何应对?
    ThinkPHP内核全行业小程序运营管理系统源码免费分享下载
    2020年不管打工还是创业,居然还有人相信读书无用论?
    在IT界,应聘企业去上班如果老板一点不懂技术那绝对是作茧自缚
    看了这篇文章你还不懂傅里叶变换,那我就真没办法呢!
  • 原文地址:https://www.cnblogs.com/renhui/p/14069812.html
Copyright © 2011-2022 走看看