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())); } }