1.Lombok簡介
大概的意思:Lombok是一個Java庫,能自動插入編輯器並構建工具,簡化Java開發。通過添加注解的方式,不需要為類編寫getter或eques方法,同時可以自動化日志變量。官網鏈接
簡而言之:Lombok能以簡單的注解形式來簡化java代碼,提高開發人員的開發效率。
博客及源碼GitHub鏈接
2.Lombok使用
使用Lombok需要的開發環境Java+Maven+IntelliJ IDEA或者Eclipse(安裝Lombok Plugin)
2.1添加maven依賴
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.4</version> <scope>provided</scope> </dependency>
2.2安裝插件
使用Lombok還需要插件的配合,我使用開發工具為idea,這里只講解idea中安裝lombok插件,使用eclipse和myeclipse的小伙伴和自行google安裝方法。
打開idea的設置,點擊Plugins,點擊Browse repositories,在彈出的窗口中搜索lombok,然后安裝即可
2.3解決編譯時出錯問題
編譯時出錯,可能是沒有enable注解處理器。Annotation Processors > Enable annotation processing
。設置完成之后程序正常運行。
2.4示例
下面舉兩個栗子,看看使用lombok和不使用的區別。
創建一個用戶類
不使用Lombok
public class User implements Serializable { private static final long serialVersionUID = -8054600833969507380L; private Integer id; private String username; private Integer age; public User() { } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", age=" + age + '}'; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } User user = (User) o; return Objects.equals(id, user.id) && Objects.equals(username, user.username) && Objects.equals(age, user.age); } @Override public int hashCode() { return Objects.hash(id, username, age); } }
使用Lombok
@Data public class User implements Serializable { private static final long serialVersionUID = -8054600833969507380L; private Integer id; private String username; private Integer age; }
編譯源文件,然后反編譯class文件,反編譯結果如下圖。說明@Data注解在類上,會為類的所有屬性自動生成setter/getter、equals、canEqual、hashCode、toString方法,如為final屬性,則不會為該屬性生成setter方法。
自動化日志變量
@Slf4j @RestController @RequestMapping(("/user")) public class UserController { @GetMapping("/getUserById/{id}") public User getUserById(@PathVariable Integer id) { User user = new User(); user.setUsername("風清揚"); user.setAge(21); user.setId(id); if (log.isInfoEnabled()) { log.info("用戶 {}", user); } return user; } }
通過反編譯可以看到@Slf4j注解生成了log日志變量(嚴格意義來說是常量),無需去聲明一個log就可以在類中使用log記錄日志。
2.5常用注解
下面介紹一下常用的幾個注解:
@Setter 注解在類或字段,注解在類時為所有字段生成setter方法,注解在字段上時只為該字段生成setter方法。 @Getter 使用方法同上,區別在於生成的是getter方法。 @ToString 注解在類,添加toString方法。 @EqualsAndHashCode 注解在類,生成hashCode和equals方法。 @NoArgsConstructor 注解在類,生成無參的構造方法。 @RequiredArgsConstructor 注解在類,為類中需要特殊處理的字段生成構造方法,比如final和被@NonNull注解的字段。 @AllArgsConstructor 注解在類,生成包含類中所有字段的構造方法。 @Data 注解在類,生成setter/getter、equals、canEqual、hashCode、toString方法,如為final屬性,則不會為該屬性生成setter方法。 @Slf4j 注解在類,生成log變量,嚴格意義來說是常量。private static final Logger log = LoggerFactory.getLogger(UserController.class);
3.Lombok工作原理
在Lombok使用的過程中,只需要添加相應的注解,無需再為此寫任何代碼。自動生成的代碼到底是如何產生的呢?
核心之處就是對於注解的解析上。JDK5引入了注解的同時,也提供了兩種解析方式。
運行時解析
運行時能夠解析的注解,必須將@Retention設置為RUNTIME,這樣就可以通過反射拿到該注解。java.lang.reflect反射包中提供了一個接口AnnotatedElement,該接口定義了獲取注解信息的幾個方法,Class、Constructor、Field、Method、Package等都實現了該接口,對反射熟悉的朋友應該都會很熟悉這種解析方式。
編譯時解析
編譯時解析有兩種機制,分別簡單描述下:
1)Annotation Processing Tool
apt自JDK5產生,JDK7已標記為過期,不推薦使用,JDK8中已徹底刪除,自JDK6開始,可以使用Pluggable Annotation Processing API來替換它,apt被替換主要有2點原因:
(1)api都在com.sun.mirror非標准包下
(2)沒有集成到javac中,需要額外運行
2)Pluggable Annotation Processing API
JSR 269自JDK6加入,作為apt的替代方案,它解決了apt的兩個問題,javac在執行的時候會調用實現了該API的程序,這樣我們就可以對編譯器做一些增強,javac執行的過程如下:
Lombok本質上就是一個實現了“JSR 269 API”的程序。在使用javac的過程中,它產生作用的具體流程如下: 1.javac對源代碼進行分析,生成了一棵抽象語法樹(AST) 2.運行過程中調用實現了“JSR 269 API”的Lombok程序 3.此時Lombok就對第一步驟得到的AST進行處理,找到@Data注解所在類對應的語法樹(AST),然后修改該語法樹(AST),增加getter和setter方法定義的相應樹節點 4.javac使用修改后的抽象語法樹(AST)生成字節碼文件,即給class增加新的節點(代碼塊)
通過讀Lombok源碼,發現對應注解的實現都在HandleXXX中,比如@Getter注解的實現在HandleGetter.handle()。還有一些其它類庫使用這種方式實現,比如Google Auto、Dagger等等。
4.Lombok的優缺點
優點: (1)能通過注解的形式自動生成構造器、getter/setter、equals、hashcode、toString等方法,提高了一定的開發效率 (2)讓代碼變得簡潔,不用過多的去關注相應的方法 (3)屬性做修改時,也簡化了維護為這些屬性所生成的getter/setter方法等
缺點: (1)不支持多種參數構造器的重載 (2)雖然省去了手動創建getter/setter方法的麻煩,但大大降低了源代碼的可讀性和完整性,降低了閱讀源代碼的舒適度
ref:lombok