面试官:你天天用 Lombok,说说它什么原理?( 二 )

Retention注解上面有一个属性value,它是RetentionPolicy类型的枚举类,RetentionPolicy枚举类中有三个值 。
public enum RetentionPolicy {SOURCE,CLASS,RUNTIME}

  • SOURCE修饰的注解:修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中
  • CLASS修饰的注解:表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候
  • RUNTIME修饰的注解:表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时 。所以它能够通过反射调用,所以正常运行时注解都是使用的这个参数
Target注解上面也有个属性value,它是ElementType类型的枚举 。是用来修饰此注解作用在哪的 。
public enum ElementType {TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE,TYPE_PARAMETER,TYPE_USE}定义注解处理器我们要定义注解处理器的话,那么就需要继承AbstractProcessor类 。继承完以后基本的框架类型如下 。
推荐一个 Spring Boot 基础教程及实战示例:
https://github.com/javastacks/spring-boot-best-practice
@SupportedSourceVersion(SourceVersion.RELEASE_8)@SupportedAnnotationTypes("aboutjava.annotion.MyGetter")public class MyGetterProcessor extends AbstractProcessor {@Overridepublic synchronized void init(ProcessingEnvironment processingEnv) {super.init(processingEnv);}@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {return true;}}我们可以看到在子类中上面有两个注解,注解描述如下
  • @SupportedSourceVersion:表示所支持的Java版本
  • @SupportedAnnotationTypes:表示该处理器要处理的注解
继承了父类的两个方法,方法描述如下
  • init方法:主要是获得编译时期的一些环境信息
  • process方法:在编译时,编译器执行的方法 。也就是我们写具体逻辑的地方
我们是演示一下如何通过继承AbstractProcessor类来实现在编译时生成类,所以我们在process方法中书写我们生成类的代码 。
如下所示 。
@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {StringBuilder builder = new StringBuilder().Append("package aboutjava.annotion;nn").append("public class GeneratedClass {nn") // open class.append("tpublic String getMessage() {n") // open method.append("ttreturn "");// for each javax.lang.model.element.Element annotated with the CustomAnnotationfor (Element element : roundEnv.getElementsAnnotatedWith(MyGetter.class)) {String objectType = element.getSimpleName().toString();// this is appending to the return statementbuilder.append(objectType).append(" says hello!\n");}builder.append("";n") // end return.append("t}n") // close method.append("}n"); // close classtry { // write the fileJavaFileObject source = processingEnv.getFiler().createSourceFile("aboutjava.annotion.GeneratedClass");Writer writer = source.openWriter();writer.write(builder.toString());writer.flush();writer.close();} catch (IOException e) {// Note: calling e.printStackTrace() will print IO errors// that occur from the file already existing after its first run, this is normal}return true;}定义使用注解的类(测试类)上面的两个类就是基本的工具类了,一个是定义了注解,一个是定义了注解处理器,接下来我们来定义一个测试类(TestAno.java) 。我们在类上面加上我们自定的注解类 。
@MyGetterpublic class TestAno {public static void main(String[] args) {System.out.printf("1");}}这样我们在编译期就能生成文件了,接下来演示一下在编译时生成文件,此时不要着急直接进行javac编译,MyGetter类是注解类没错,而MyGetterProcessor是注解类的处理器,那么我们在编译TestAnoJava文件的时候就会触发处理器 。因此这两个类是无法一起编译的 。
先给大家看一下我的目录结构
aboutjava-- annotion-- MyGetter.java-- MyGetterProcessor.java-- TestAno.java所以我们先将注解类和注解处理器类进行编译
javac aboutjava/annotion/MyGett*接下来进行编译我们的测试类,此时在编译时需要加上processor参数,用来指定相关的注解处理类 。
javac -processor aboutjava.annotion.MyGetterProcessor aboutjava/annotion/TestAno.java大家可以看到动态图中,自动生成了Java文件 。
面试官:你天天用 Lombok,说说它什么原理?


推荐阅读