java学习-annotation-APT增强

从java 1.7开始之后, java并不在提供原生的 apt 工具, 而是提供了丰富的 API来进行支持

对于APT和 reflect 的主要区别在于, 对于 reflect 是属于运行时增强,而 APT是在编译时增强, 相对比而言, 前端编译时增强对性能损耗最小,因为对于用户而言是无感知的;

例如: spring-data 的 @Repository 和 lombok 的 @Slf4j 或 spring 的 @Compent;

对于这些增强的实现都是扩展了 javax.annotation.processing.Processor 接口或通过 javax.annotation.processing.AbstractProcessor间接扩展

对于其操作原理就是 通过 javax.tools.JavaCompiler 和 javax.tools.StandardJavaFileManager 等工具类首先自定义class编译;

并自定义实现或扩展 Processor 相关,通过 SPI的方式暴露当前实现类;

并通过 JAVA Language Module API来解析相关自定义编译class的相关元信息,实现前端编译阶段的字节码增强

 

 

TODO : WAIT CODE 

 

/*
 * Copyright (c) 2020, guoxing, Co,. Ltd. All Rights Reserved
 */
package com.xingguo.apt.annotation.process;

import com.xingguo.reflection.application.Repository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.index.processor.CandidateComponentsIndexer;
import org.springframework.stereotype.Component;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.Writer;
import java.util.*;

/**
 * 处理{@link Repository}
 * learn from {@link CandidateComponentsIndexer}
 * 参考 CandidateComponentsIndexer 将使用了{@link Component} 注解的资源进行解析并生成到 {@link org.springframework.context.index.processor.MetadataStore#METADATA_PATH} 目录下, {@link org.springframework.context.index.processor.CandidateComponentsIndexer#getSupportedAnnotationTypes()} 和我们当前自定义的不同点在于 这里是将所有类型的注解都会扫描到,并没有限制为 {@link Component}
 * <p>
 * 1:扩展 javax.annotation.processing.AbstractProcessor
 * 2:指定要处理的注解类名(集合)
 * 3:指定支持的JDK版本
 * 4:指定支持的 processor com.xingguo.reflection.application.Repository 参数可选
 * 5:通过JAVA SPI 指定当前类 为 javax.annotation.processing.Processor 的实现类
 */
@SupportedAnnotationTypes(RepositoryAnnotationProcessor.REPOSITORY_ANNOTATION_TYPE)
@SupportedSourceVersion(SourceVersion.RELEASE_8) // 表示大于等于 JDK8
@Slf4j // 其操作整体也是类似的操作
public class RepositoryAnnotationProcessor extends AbstractProcessor {
    public final static String REPOSITORY_ANNOTATION_TYPE = "com.xingguo.reflection.application.Repository";
    private final static String USER_REPOSITORY_TYPE = "com.xingguo.reflection.application.UserRepository";

    /**
     * 存储 userRepository 泛型参数
     * key 为 UserRepository 实现类
     * value为泛型参数具体类型
     */
    private Map<String, String> userRepositoryParameterizedTypesMapping = new HashMap<>();

    /**
     * {@inheritDoc}
     *
     * @param annotations
     * @param roundEnv
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        // processor 1: 处理阶段
        // 获取所有的编译类
        roundEnv.getRootElements()
                .stream()
                .filter(element -> isAnnotationPresent(element, REPOSITORY_ANNOTATION_TYPE)) // 进行注解类型过滤
                .forEach(this::processorAnnotatedElement);                     // 处理匹配到的类


        // processor 2: 完成阶段
        if (roundEnv.processingOver()) {
            // 当解析到源信息后 需要对这些数据进行处理 ,修改相关的class文件
            // 获得当前所有的classPath ,包含 项目自动编译的以及通过CompilerApi进行编译的
            generatedUserRepositoryImpl();
        }

        // 输出注解
        annotations.forEach(annotation -> {
            log.info("{}", annotation);
        });
        return false;
    }

    /**
     * 修改 UserRepositoryImpl 相关 class来进行提升
     */
    private void generatedUserRepositoryImpl() {
        Map<String, String> options = processingEnv.getOptions();
        // 获取文件管理器
        Filer filer = processingEnv.getFiler();
        // 指定自定义配置文件输出目录
        String resourceName = "META-INF/user-repository-impl.properties";
        try {
            // 创建一个资源文件存储得到的泛型参数具体类型数据
            FileObject resource = filer.createResource(StandardLocation.CLASS_OUTPUT, "", resourceName);
            try (Writer writer = resource.openWriter();) {
                Properties properties = new Properties();
                properties.putAll(userRepositoryParameterizedTypesMapping);
                properties.store(writer, "generated by RepositoryAnnotationProcessor");

            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Locale locale = processingEnv.getLocale();
        Messager messager = processingEnv.getMessager();
        log.info("{},{},{},{}", options, filer, locale, messager);

    }

    /**
     * 对于apt 和 reflect 的区别在于
     * apt 是在前端编译阶段发生的,而reflect 是在 jvm 运行时进行的;
     * 相对比而言,运行时的性能损耗会更加明显
     */

    /**
     * 处理当前匹配到(使用指定注解)的类
     *
     * @param element
     */
    public void processorAnnotatedElement(Element element) {
        if (isConcreteClass(element) && isUserRepositoryType(element)) {
            // 输出当前实现类
            log.info("当前具体实现了userRepository的类{}", element);
            //获取UserRepository接口的genericType
            TypeMirror genericUserRepositoryType = getGenericUserRepositoryType(element);
            log.info("当前实现具体的定义{}", genericUserRepositoryType);
            //  获取泛型参数 类似于 <@link java.lang.reflect.ParameterizedType>
            // javax.lang.model.type.DeclaredType.getTypeArguments
            if (genericUserRepositoryType instanceof DeclaredType) {
                DeclaredType declaredType = (DeclaredType) genericUserRepositoryType;
                declaredType.getTypeArguments()
                        .stream()
                        .forEach(typeMirror -> {
                            userRepositoryParameterizedTypesMapping.put(genericUserRepositoryType.toString(), typeMirror.toString());
                            log.info("得到的泛型具体参数{}", typeMirror);
                        });
            }
        }


    }

    /**
     * 获取当前element 实现的 UserRepository 具体数据,包含泛型参数的实现定义
     *
     * @param element
     * @return
     */
    public TypeMirror getGenericUserRepositoryType(Element element) {
        ElementKind kind = element.getKind();
        if (kind.isClass() && element instanceof TypeElement) {
            // 强转为 typeElement ; 标记当前类型为 一个class 或 interface
            TypeElement typeElement = (TypeElement) element;
            // 获取当前 element 实现的全部接口
            List<? extends TypeMirror> interfaces = typeElement.getInterfaces();
            return interfaces.stream()
                    .filter(typeMirror -> Objects.equals(USER_REPOSITORY_TYPE, processingEnv.getTypeUtils().erasure(typeMirror).toString()))
                    .findFirst()
                    .orElse(null);
        }
        return null;
    }

    /**
     * 判断当前element 是否实现了 userRepository
     *
     * @param element
     * @return
     */
    public boolean isUserRepositoryType(Element element) {
        ElementKind kind = element.getKind();
        if (kind.isClass() && element instanceof TypeElement) {
            TypeElement typeElement = (TypeElement) element;
            /**
             * 对于 abstractProcessor中 存在 processingEnv 可以使用
             */
            Types typeUtils = processingEnv.getTypeUtils();
            Elements elementUtils = processingEnv.getElementUtils();
            // 获取当前类实现的接口
            List<? extends TypeMirror> interfaces = typeElement.getInterfaces();
//            testUtil(interfaces);
            return interfaces.stream()
                    // 判断当前接口的类型是否包含当前 指定的接口类型; 对于当前的typeMirror 是包含泛型具体数据;
                    // 因此需要得到擦写后的数据才能进行匹配操作
                    .anyMatch(typeMirror -> Objects.equals(USER_REPOSITORY_TYPE, typeUtils.erasure(typeMirror).toString()));
        }
        return false;
    }

    private void testUtil(List<? extends TypeMirror> interfaces) {
        Types typeUtils = processingEnv.getTypeUtils();
        interfaces.stream().forEach(typeMirror -> {

            // 对于 当前 typeMirror是存在泛型的具体类型
            log.info("typeMirror:{}", typeMirror);
            // 使用工具对泛型参数进行擦写
            TypeMirror erasure = typeUtils.erasure(typeMirror);
            log.info("erasureTypeMirror:{}", erasure);
            if (typeMirror instanceof DeclaredType) {
                DeclaredType declaredType = (DeclaredType) typeMirror;

                /**
                 * 对于type 和 element 而言, type 是无状态的, 而element是有状态的, 例如泛型, 对于type而言得到的就是泛型的原始定义,而对于一个具体的类 element 得到的就是单纯的类定义
                 */
                Element interfaceElement = declaredType.asElement();
                TypeMirror interfaceType = interfaceElement.asType();
                log.info("element:{};type:{}", interfaceElement, interfaceType);
            }
        });
    }

    /**
     * 判断当前是否为一个具体实现类(而非抽象)
     *
     * @param element
     * @return
     */
    public boolean isConcreteClass(Element element) {
        return !element.getModifiers().contains(Modifier.ABSTRACT);
    }

    /**
     * {@link Class#isAnnotationPresent(java.lang.Class)}
     * <p>
     * 根据element 来匹配是否存在当前注解
     */

    public boolean isAnnotationPresent(Element element, String annotationClassName) {
        if (Objects.isNull(element)) {
            return false;
        }
        return element.getAnnotationMirrors() // 获取当前元素的全部注解镜像
                .stream()
                // 要求匹配当前元素的注解类型包含当前要处理的 ANNOTATION_TYPES
                .anyMatch(annotationMirror -> Objects.equals(annotationClassName, annotationMirror.getAnnotationType().toString()));

    }


}

 

posted @ 2020-11-27 22:14  郭星  阅读(385)  评论(0)    收藏  举报