lombok如何做的冗余代码消除。

文章估计一时半会写不完。lombok的原理还是挺有意思的

先说说注解吧。来自官方的文档。(地址:https://docs.oracle.com/javase/tutorial/java/annotations/
这里写图片描述

这里有三句话:
①:Information for the compiler — Annotations can be used by the compiler to detect errors or suppress warnings
注解可以用来被编译器检测错误或者阻止错误。

②:Compile-time and deployment-time processing — Software tools can process annotation information to generate code, XML files, and so forth
软件工具可以处理注解信息生成代码 xml文件
③:Runtime processing — Some annotations are available to be examined at runtime
一些注解可以在运行时检测。

这里的③,其实就是我们在spring中经常见到了。其中①就像我们平时用的@override是用来给javac看的。

再看一下javac的参数:

C:\Program Files\Java\jdk1.7.0_75\bin>javac
用法: javac <options> <source files>
其中, 可能的选项包括:
  -g                         生成所有调试信息
  -g:none                    不生成任何调试信息
  -g:{lines,vars,source}     只生成某些调试信息
  -nowarn                    不生成任何警告
  -verbose                   输出有关编译器正在执行的操作的消息
  -deprecation               输出使用已过时的 API 的源位置
  -classpath <路径>            指定查找用户类文件和注释处理程序的位置
  -cp <路径>                   指定查找用户类文件和注释处理程序的位置
  -sourcepath <路径>           指定查找输入源文件的位置
  -bootclasspath <路径>        覆盖引导类文件的位置
  -extdirs <目录>              覆盖所安装扩展的位置
  -endorseddirs <目录>         覆盖签名的标准路径的位置
  -proc:{none,only}          控制是否执行注释处理和/或编译。
  -processor <class1>[,<class2>,<class3>...] 要运行的注释处理程序的名称; 绕过默
认的搜索进程
  -processorpath <路径>        指定查找注释处理程序的位置
  -d <目录>                    指定放置生成的类文件的位置
  -s <目录>                    指定放置生成的源文件的位置
  -implicit:{none,class}     指定是否为隐式引用文件生成类文件
  -encoding <编码>             指定源文件使用的字符编码
  -source <发行版>              提供与指定发行版的源兼容性
  -target <发行版>              生成特定 VM 版本的类文件
  -version                   版本信息
  -help                      输出标准选项的提要
  -A关键字[=值]                  传递给注释处理程序的选项
  -X                         输出非标准选项的提要
  -J<标记>                     直接将 <标记> 传递给运行时系统
  -Werror                    出现警告时终止编译
  @<文件名>                     从文件读取选项和文件名


C:\Program Files\Java\jdk1.7.0_75\bin>

其中
-classpath <路径> 指定查找用户类文件和注释处理程序的位置
-cp <路径> 指定查找用户类文件和注释处理程序的位置
足可以看出第①个的作用。

===========
先看一个注解改为javac行为的例子。
代码来自网络.
这里写图片描述

贴代码:

import faicm.PrintMe;
public class A {
    public static void main(String[] args) {
        aa();
    }
    @PrintMe
    private static void aa() {
    }
}
package faicm;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;

@SupportedAnnotationTypes({"faicm.PrintMe"})
public class MyProcessor extends AbstractProcessor {
    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment env) {
        Messager messager = processingEnv.getMessager();
        for (TypeElement te : annotations) {
            for (Element e : env.getElementsAnnotatedWith(te)) {
                messager.printMessage(Diagnostic.Kind.NOTE, "zouqi  "
                        + "Printing: " + e.toString());
            }
        }
        return true;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}

继续

package faicm;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.SOURCE)
public @interface PrintMe {
}

继续
javax.annotation.processing.Processor文件里面就一句话
faicm.MyProcessor

MANIFEST.MF文件 就一句话 Manifest-Version: 1.0

打包成jar后。如下:

C:\Program Files\Java\jdk1.7.0_75\bin>javac -cp ann.jar A.java
注: zouqi  Printing: aa()

C:\Program Files\Java\jdk1.7.0_75\bin>

第二个知识点:

在jar里面有这么一个接口和类:

package faicm;
public interface Animal {
    public void say();
}

==

package faicm;
public class Dog implements Animal {
    public void say() {
        System.out.println("dog");
    }
}

=

package faicm;
public class Cat implements Animal {
    public void say() {
        System.out.println("cat");
    }
}

在项目下有一个文件夹META-INF/services 下有faicm.Animal文件
里面就两句话:
faicm.Dog
faicm.Cat

把项目打jar后,在另一个项目中

public class Main {
    public static void main(String[] args) {
        ServiceLoader<Animal> loder = ServiceLoader.load(Animal.class);
        for (Animal animal : loder) {
            System.out.println(animal.getClass());
            animal.say();
        }
    }
}
interface Animal {
    public void say();

就能看到输出了。

在lombok.jar中可以看到这个文件:
javax.annotation.processing.Processor
里面的内容是
lombok.launch.AnnotationProcessorHider$AnnotationProcessor
其中Processor在api中可以查到。AnnotationProcessor这个类就是lombok工作的类。

https://github.com/rzwitserloot/lombok/blob/a7e3d5070eb0116e5b80e4f8a96d176a2127fc19/src/launch/lombok/launch/AnnotationProcessor.java

其中就是这句作为入口
return instance.process(annotations, roundEnv);

这句会调用到
https://github.com/rzwitserloot/lombok/blob/a7e3d5070eb0116e5b80e4f8a96d176a2127fc19/src/core/lombok/core/AnnotationProcessor.java
中的

@Override boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
            return processor.process(annotations, roundEnv);
        }


https://github.com/rzwitserloot/lombok/blob/a7e3d5070eb0116e5b80e4f8a96d176a2127fc19/src/core/lombok/javac/apt/Processor.java
中的

Processor.java类的

public boolean process(Set <? extends TypeElement> annotations, RoundEnvironment roundEnv) 

这个方法开始和javac打交道。

javac中是怎么样的呢。未完待续。。。

继续写:

一:下载openjdk源码openjdk-7u40-fcs-src-b43-26_aug_2013.zip 解压后把openjdk\langtools\src\share\classes 这个文件夹里面的所有文件放到eclipse项目src下,如果报错。调整一下jdk就行了。
二:下载lombok的jar文件lombok-1.16.4.jar,打进项目。
三:创建类放在d盘:

import lombok.Setter;
public class Person {
    @Setter
    private String name;
    @Setter
    private int age;
}

然后在项目中找到类com.sun.tools.javac下的Main执行主方法,加参数d:/Person.java,运行后生成class文件,反编译后看到:

public class Person
{
  private String name;
  private int age;

  public void setName(String paramString)
  {
    this.name = paramString;
  }
  public void setAge(int paramInt) { this.age = paramInt; }

}

好了,环境就是这样搞ok。

在lombok.launch下的AnnotationProcessorHider中的@Override public boolean process里面debug就进去了。

在openjdk里面:
JavacProcessingEnvironment 中有一个内部类是ServiceIterator 。

ServiceIterator 构造方法

loaderClass = Class.forName(“java.util.ServiceLoader”);
loadMethodName = “load”;
jusl = true;

这个就是对应了上面的知识点2:如下图:
这里写图片描述

未完待续。

这里写图片描述

如图,会经过这个方法

public JavaCompiler processAnnotations(List<JCCompilationUnit> roots,
                                           List<String> classnames) {
        if (shouldStop(CompileState.PROCESS)) {
            // Errors were encountered.
            // Unless all the errors are resolve errors, the errors were parse errors
            // or other errors during enter which cannot be fixed by running
            // any annotation processors.
            if (unrecoverableError()) {
                log.reportDeferredDiagnostics();
                return this;
            }
        }

第一个参数是一个AST,

 JavaCompiler c = procEnvImpl.doProcessing(context, roots, classSymbols, pckSymbols);
   boolean errorStatus;
        boolean moreToDo;
        do {
            // Run processors for round n
            round.run(false, false);
   discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles);

这里写图片描述

if (matchedNames.size() > 0 || ps.contributed) {
boolean processingResult = callProcessor(ps.processor, typeElements, renv);
ps.contributed = true;
ps.removeSupportedOptions(unmatchedProcessorOptions);

if (printProcessorInfo || verbose) {
log.printNoteLines("x.print.processor.info",
ps.processor.getClass().getName(),
matchedNames.toString(),
processingResult);
}

if (processingResult) {
 unmatchedAnnotations.keySet().removeAll(matchedNames);
}

}

继续走

这里写图片描述

lombok的jar在eclipse进不去,所以可以断点看不到代码。

未完待续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值