<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:你天天用 Lombok,說(shuō)說(shuō)它什么原理?我竟然答不上來(lái)…

          共 9232字,需瀏覽 19分鐘

           ·

          2022-06-29 16:06

          關(guān)注我們,設(shè)為星標(biāo),每天7:40不見不散,架構(gòu)路上與您共享

          回復(fù)架構(gòu)師獲取資源


          大家好,我是你們的朋友架構(gòu)君,一個(gè)會(huì)寫代碼吟詩(shī)的架構(gòu)師。

          'javajgs.com';


          • Lombok如何使用
            • 功能
          • 編譯時(shí)注解
          • 注解處理工具apt
            • 定義注解
            • 定義注解處理器
            • 定義使用注解的類(測(cè)試類)

          相信大家在項(xiàng)目中都使用過(guò)Lombok,因?yàn)槟軌蚝?jiǎn)化我們?cè)S多的代碼,但是該有的功能一點(diǎn)也不少。

          那么lombok到底是個(gè)什么呢,lombok是一個(gè)可以通過(guò)簡(jiǎn)單的注解的形式來(lái)幫助我們簡(jiǎn)化消除一些必須有但顯得很臃腫的 Java 代碼的工具,簡(jiǎn)單來(lái)說(shuō),比如我們新建了一個(gè)類,然后在其中寫了幾個(gè)字段,然后通常情況下我們需要手動(dòng)去建立getter和setter方法啊,構(gòu)造函數(shù)啊之類的,lombok的作用就是為了省去我們手動(dòng)創(chuàng)建這些代碼的麻煩,它能夠在我們編譯源碼的時(shí)候自動(dòng)幫我們生成這些方法。

          那么Lombok到底是如何做到這些的呢?其實(shí)底層就是用到了編譯時(shí)注解的功能。

          Lombok如何使用

          Lombok是一個(gè)開源項(xiàng)目,代碼是在lombok中,如果是gradle項(xiàng)目的話直接在項(xiàng)目中引用如下即可。

          compile ("org.projectlombok:lombok:1.16.6")

          功能

          那么Lombok是做什么呢?其實(shí)很簡(jiǎn)單,一個(gè)最簡(jiǎn)單的例子就是能夠通過(guò)添加注解自動(dòng)生成一些方法,使我們代碼更加簡(jiǎn)潔易懂。例如下面一個(gè)類。

           1 @Data
           2 public class TestLombok {
           3    private String name;
           4    private Integer age;
           5
           6    public static void main(String[] args) {
           7        TestLombok testLombok = new TestLombok();
           8        testLombok.setAge(12);
           9        testLombok.setName("zs");
          10    }
          11 }

          我們使用Lombok提供的Data注解,在沒(méi)有寫get、set方法的時(shí)候也能夠使用其get、set方法。我們看它編譯過(guò)后的class文件,可以看到它給我們自動(dòng)生成了get、set方法。

           1 public class TestLombok {
           2    private String name;
           3    private Integer age;
           4
           5    public static void main(String[] args) {
           6        TestLombok testLombok = new TestLombok();
           7        testLombok.setAge(12);
           8        testLombok.setName("zs");
           9    }
          10
          11    public TestLombok() {
          12    }
          13
          14    public String getName() {
          15        return this.name;
          16    }
          17
          18    public Integer getAge() {
          19        return this.age;
          20    }
          21
          22    public void setName(String name) {
          23        this.name = name;
          24    }
          25
          26    public void setAge(Integer age) {
          27        this.age = age;
          28    }
          29
          30}

          當(dāng)然Lombok的功能不止如此,還有很多其他的注解幫助我們簡(jiǎn)便開發(fā),網(wǎng)上有許多的關(guān)于Lombok的使用方法,這里就不再啰嗦了。正常情況下我們?cè)陧?xiàng)目中自定義注解,或者使用Spring框架中@Controller、@Service等等這類注解都是運(yùn)行時(shí)注解,運(yùn)行時(shí)注解大部分都是通過(guò)反射來(lái)實(shí)現(xiàn)的。而Lombok是使用編譯時(shí)注解實(shí)現(xiàn)的。那么編譯時(shí)注解是什么呢?

          編譯時(shí)注解

          注解(也被成為元數(shù)據(jù))為我們?cè)诖a中添加信息提供了一種形式化的方法,使我們可以在稍后某個(gè)時(shí)刻非常方便地使用這些數(shù)據(jù)。——————摘自《Thinking in Java》

          Java中的注解分為運(yùn)行時(shí)注解編譯時(shí)注解 ,運(yùn)行時(shí)注解就是我們經(jīng)常使用的在程序運(yùn)行時(shí)通過(guò)反射得到我們注解的信息,然后再做一些操作。而編譯時(shí)注解是什么呢?就是在程序在編譯期間通過(guò)注解處理器進(jìn)行處理。

          • 編譯期:Java語(yǔ)言的編譯期是一段不確定的操作過(guò)程,因?yàn)樗赡苁菍?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(22, 123, 194);">*.java文件轉(zhuǎn)化成*.class文件的過(guò)程;也可能是指將字節(jié)碼轉(zhuǎn)變成機(jī)器碼的過(guò)程;還可能是直接將*.java編譯成本地機(jī)器代碼的過(guò)程
          • 運(yùn)行期:從JVM加載字節(jié)碼文件到內(nèi)存中,到最后使用完畢以后卸載的過(guò)程都屬于運(yùn)行期的范疇。

          注解處理工具apt

          注解處理工具apt(Annotation Processing Tool),這是Sun為了幫助注解的處理過(guò)程而提供的工具,apt被設(shè)計(jì)為操作Java源文件,而不是編譯后的類。

          它是javac的一個(gè)工具,中文意思為編譯時(shí)注解處理器。APT可以用來(lái)在編譯時(shí)掃描和處理注解。通過(guò)APT可以獲取到注解和被注解對(duì)象的相關(guān)信息,在拿到這些信息后我們可以根據(jù)需求來(lái)自動(dòng)的生成一些代碼,省去了手動(dòng)編寫。注意,獲取注解及生成代碼都是在代碼編譯 時(shí)候完成的,相比反射在運(yùn)行時(shí)處理注解大大提高了程序性能。APT的核心是AbstractProcessor類。

          正常情況下使用APT工具只是能夠生成一些文件(不僅僅是我們想象的class文件,還包括xml文件等等之類的 ),并不能修改原有的文件信息。

          但是此時(shí)估計(jì)會(huì)有疑問(wèn),那么Lombok不就是在我們?cè)械奈募行略隽艘恍┬畔幔课以诤竺鏁?huì)有詳細(xì)的解釋,這里簡(jiǎn)單介紹一下,其實(shí)Lombok是修改了Java中的抽象語(yǔ)法樹AST 才做到了修改其原有類的信息。

          接下來(lái)我們演示一下如何用APT工具生成一個(gè)class文件,然后我們?cè)僬f(shuō)Lombok是如何修改已存在的類中的屬性的。

          定義注解

          首先當(dāng)然我們需要定義自己的注解了

          1 @Retention(RetentionPolicy.SOURCE)
          2 @Target(ElementType.TYPE)
          3 public @interface GeneratePrint {
          4
          5    String value();
          6 }

          Retention注解上面有一個(gè)屬性value,它是RetentionPolicy類型的枚舉類,RetentionPolicy枚舉類中有三個(gè)值。

          1 public enum RetentionPolicy {
          2
          3    SOURCE,
          4
          5    CLASS,
          6
          7    RUNTIME
          8 }
          • SOURCE修飾的注解:修飾的注解,表示注解的信息會(huì)被編譯器拋棄,不會(huì)留在class文件中,注解的信息只會(huì)留在源文件中
          • CLASS修飾的注解:表示注解的信息被保留在class文件(字節(jié)碼文件)中當(dāng)程序編譯時(shí),但不會(huì)被虛擬機(jī)讀取在運(yùn)行的時(shí)候
          • RUNTIME修飾的注解:表示注解的信息被保留在class文件(字節(jié)碼文件)中當(dāng)程序編譯時(shí),會(huì)被虛擬機(jī)保留在運(yùn)行時(shí)。所以它能夠通過(guò)反射調(diào)用,所以正常運(yùn)行時(shí)注解都是使用的這個(gè)參數(shù)

          Target注解上面也有個(gè)屬性value,它是ElementType類型的枚舉。是用來(lái)修飾此注解作用在哪的。

           1 public enum ElementType {
           2    TYPE,
           3
           4    FIELD,
           5
           6    METHOD,
           7
           8    PARAMETER,
           9
          10    CONSTRUCTOR,
          11
          12    LOCAL_VARIABLE,
          13
          14    ANNOTATION_TYPE,
          15
          16    PACKAGE,
          17
          18    TYPE_PARAMETER,
          19
          20    TYPE_USE
          21 }

          定義注解處理器

          我們要定義注解處理器的話,那么就需要繼承AbstractProcessor類。繼承完以后基本的框架類型如下

           1 @SupportedSourceVersion(SourceVersion.RELEASE_8)
           2 @SupportedAnnotationTypes("aboutjava.annotion.MyGetter")
           3 public class MyGetterProcessor extends AbstractProcessor {
           4    @Override
           5    public synchronized void init(ProcessingEnvironment processingEnv) {
           6    super.init(processingEnv);
           7    }
           8
           9    @Override
          10    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
          11        return true;
          12    }
          13 }

          我們可以看到在子類中上面有兩個(gè)注解,注解描述如下

          • @SupportedSourceVersion:表示所支持的Java版本
          • @SupportedAnnotationTypes:表示該處理器要處理的注解

          繼承了父類的兩個(gè)方法,方法描述如下

          • init方法:主要是獲得編譯時(shí)期的一些環(huán)境信息
          • process方法:在編譯時(shí),編譯器執(zhí)行的方法。也就是我們寫具體邏輯的地方

          我們是演示一下如何通過(guò)繼承AbstractProcessor類來(lái)實(shí)現(xiàn)在編譯時(shí)生成類,所以我們?cè)?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(22, 123, 194);">process方法中書寫我們生成類的代碼。如下所示。

           1 @Override
           2 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
           3    StringBuilder builder = new StringBuilder()
           4            .append("package aboutjava.annotion;\n\n")
           5            .append("public class GeneratedClass {\n\n")
           6            .append("\tpublic String getMessage() {\n")
           7            .append("\t\treturn \"");
           8
           9    for (Element element : roundEnv.getElementsAnnotatedWith(MyGetter.class)) {
          10        String objectType = element.getSimpleName().toString();
          11
          12        builder.append(objectType).append(" says hello!\\n");
          13    }
          14    builder.append("\";\n")
          15            .append("\t}\n")
          16            .append("}\n");
          17    try {
          18        JavaFileObject source = processingEnv.getFiler().createSourceFile("aboutjava.annotion.GeneratedClass");
          19        Writer writer = source.openWriter();
          20        writer.write(builder.toString());
          21        writer.flush();
          22        writer.close();
          23    } catch (IOException e) {
          24
          25
          26    }
          27    return true;
          28 }

          定義使用注解的類(測(cè)試類)

          上面的兩個(gè)類就是基本的工具類了,一個(gè)是定義了注解,一個(gè)是定義了注解處理器,接下來(lái)我們來(lái)定義一個(gè)測(cè)試類(TestAno.java)。我們?cè)陬惿厦婕由衔覀冏远ǖ淖⒔忸悺?/p>

          1 @MyGetter
          2 public class TestAno {
          3
          4    public static void main(String[] args) {
          5        System.out.printf("1");
          6    }
          7 }

          這樣我們?cè)诰幾g期就能生成文件了,接下來(lái)演示一下在編譯時(shí)生成文件,此時(shí)不要著急直接進(jìn)行javac編譯,MyGetter類是注解類沒(méi)錯(cuò),而MyGetterProcessor是注解類的處理器,那么我們?cè)诰幾gTestAnoJava文件的時(shí)候就會(huì)觸發(fā)處理器。因此這兩個(gè)類是無(wú)法一起編譯的。

          先給大家看一下我的目錄結(jié)構(gòu)

          aboutjava2
          -- annotion3
          -- MyGetter.java4
          -- MyGetterProcessor.java5
          -- TestAno.java

          所以我們先將注解類和注解處理器類進(jìn)行編譯

          javac aboutjava/annotion/MyGett*

          接下來(lái)進(jìn)行編譯我們的測(cè)試類,此時(shí)在編譯時(shí)需要加上processor參數(shù),用來(lái)指定相關(guān)的注解處理類。

          javac -processor aboutjava.annotion.MyGetterProcessor aboutjava/annotion/TestAno.java

          大家可以看到動(dòng)態(tài)圖中,自動(dòng)生成了Java文件。

          圖片



          文章來(lái)源:juejin.im/post/5e54d38a6fb9a07cbf46b3ca


          到此文章就結(jié)束了。Java架構(gòu)師必看一個(gè)集公眾號(hào)、小程序、網(wǎng)站(3合1的文章平臺(tái),給您架構(gòu)路上一臂之力,javajgs.com)。如果今天的文章對(duì)你在進(jìn)階架構(gòu)師的路上有新的啟發(fā)和進(jìn)步,歡迎轉(zhuǎn)發(fā)給更多人。歡迎加入架構(gòu)師社區(qū)技術(shù)交流群,眾多大咖帶你進(jìn)階架構(gòu)師,在后臺(tái)回復(fù)“加群”即可入群。



          這些年小編給你分享過(guò)的干貨


          1.idea永久激活碼(親測(cè)可用)

          2.優(yōu)質(zhì)ERP系統(tǒng)帶進(jìn)銷存財(cái)務(wù)生產(chǎn)功能(附源碼)

          3.優(yōu)質(zhì)SpringBoot帶工作流管理項(xiàng)目(附源碼)

          4.最好用的OA系統(tǒng),拿來(lái)即用(附源碼)

          5.SBoot+Vue外賣系統(tǒng)前后端都有(附源碼

          6.SBoot+Vue可視化大屏拖拽項(xiàng)目(附源碼)


          轉(zhuǎn)發(fā)在看就是最大的支持??

          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  高清无码理论 | 天天艹在线观看 | 男女拍拍视频免费 | 亚洲欧美日韩黄色大片 | 疼啊……草啊……视频 |