Lombok為啥這么牛逼?SpringBoot和IDEA官方都要支持它
最近 IDEA 2020最后一個(gè)版本發(fā)布了 ,已經(jīng)內(nèi)置了Lombok插件,SpringBoot 2.1.x之后的版本也在Starter中內(nèi)置了Lombok依賴(lài)。為什么他們都要支持Lombok呢?今天我來(lái)講講Lombok的使用,看看它有何神奇之處!
Lombok簡(jiǎn)介
Lombok是一款Java代碼功能增強(qiáng)庫(kù),在Github上已有9.8k+Star。它會(huì)自動(dòng)集成到你的編輯器和構(gòu)建工具中,從而使你的Java代碼更加生動(dòng)有趣。通過(guò)Lombok的注解,你可以不用再寫(xiě)getter、setter、equals等方法,Lombok將在編譯時(shí)為你自動(dòng)生成。
Lombok集成
首先我們需要在IDEA中安裝好Lombok插件,如果你使用的是最新版IDEA 2020.3,則Lombok插件已經(jīng)內(nèi)置,無(wú)需安裝。

之后在項(xiàng)目的pom.xml文件中添加Lombok依賴(lài),SpringBoot 2.1.x版本后無(wú)需指定Lombok版本,SpringBoot在 spring-boot-dependencies 中已經(jīng)內(nèi)置。
<!--lombok依賴(lài)--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
Lombok使用
Lombok中有很多注解,這些注解使得我們可以更加方便的編寫(xiě)Java代碼,下面介紹下這些注解的使用。
val
使用val注解可以取代任意類(lèi)型作為局部變量,這樣我們就不用寫(xiě)復(fù)雜的ArrayList和Map.Entry類(lèi)型了,具體例子如下。
/**
* Created by macro on 2020/12/16.
*/
public class ValExample {
public static void example() {
//val代替ArrayList<String>和String類(lèi)型
val example = new ArrayList<String>();
example.add("Hello World!");
val foo = example.get(0);
System.out.println(foo.toLowerCase());
}
public static void example2() {
//val代替Map.Entry<Integer,String>類(lèi)型
val map = new HashMap<Integer, String>();
map.put(0, "zero");
map.put(5, "five");
for (val entry : map.entrySet()) {
System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());
}
}
public static void main(String[] args) {
example();
example2();
}
}
當(dāng)我們使用了val注解后,Lombok會(huì)從局部變量的初始化表達(dá)式推斷出具體類(lèi)型,編譯后會(huì)生成如下代碼。
public class ValExample {
public ValExample() {
}
public static void example() {
ArrayList<String> example = new ArrayList();
example.add("Hello World!");
String foo = (String)example.get(0);
System.out.println(foo.toLowerCase());
}
public static void example2() {
HashMap<Integer, String> map = new HashMap();
map.put(0, "zero");
map.put(5, "five");
Iterator var1 = map.entrySet().iterator();
while(var1.hasNext()) {
Entry<Integer, String> entry = (Entry)var1.next();
System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());
}
}
}
@NonNull
在方法上使用@NonNull注解可以做非空判斷,如果傳入空值的話會(huì)直接拋出NullPointerException。
/**
* Created by macro on 2020/12/16.
*/
public class NonNullExample {
private String name;
public NonNullExample(@NonNull String name){
this.name = name;
}
public static void main(String[] args) {
new NonNullExample("test");
//會(huì)拋出NullPointerException
new NonNullExample(null);
}
}
編譯后會(huì)在構(gòu)造器中添加非空判斷,具體代碼如下。
public class NonNullExample {
private String name;
public NonNullExample(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked non-null but is null");
} else {
this.name = name;
}
}
public static void main(String[] args) {
new NonNullExample("test");
new NonNullExample((String)null);
}
}
@Cleanup
當(dāng)我們?cè)贘ava中使用資源時(shí),不可避免地需要在使用后關(guān)閉資源。使用@Cleanup注解可以自動(dòng)關(guān)閉資源。
/**
* Created by macro on 2020/12/16.
*/
public class CleanupExample {
public static void main(String[] args) throws IOException {
String inStr = "Hello World!";
//使用輸入輸出流自動(dòng)關(guān)閉,無(wú)需編寫(xiě)try catch和調(diào)用close()方法
@Cleanup ByteArrayInputStream in = new ByteArrayInputStream(inStr.getBytes("UTF-8"));
@Cleanup ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] b = new byte[1024];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
String outStr = out.toString("UTF-8");
System.out.println(outStr);
}
}
編譯后Lombok會(huì)生成如下代碼。
public class CleanupExample {
public CleanupExample() {
}
public static void main(String[] args) throws IOException {
String inStr = "Hello World!";
ByteArrayInputStream in = new ByteArrayInputStream(inStr.getBytes("UTF-8"));
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
byte[] b = new byte[1024];
while(true) {
int r = in.read(b);
if (r == -1) {
String outStr = out.toString("UTF-8");
System.out.println(outStr);
return;
}
out.write(b, 0, r);
}
} finally {
if (Collections.singletonList(out).get(0) != null) {
out.close();
}
}
} finally {
if (Collections.singletonList(in).get(0) != null) {
in.close();
}
}
}
}
@Getter/@Setter
有了@Getter/@Setter注解,我們?cè)僖膊挥镁帉?xiě)getter/setter方法了。試想下之前即使我們使用IDEA自動(dòng)生成getter/setter方法,如果類(lèi)屬性的類(lèi)型和名稱(chēng)改了,又要重新生成getter/setter方法也是一件很麻煩的事情。
/**
* Created by macro on 2020/12/17.
*/
public class GetterSetterExample {
@Getter
@Setter
private String name;
@Getter
@Setter(AccessLevel.PROTECTED)
private Integer age;
public static void main(String[] args) {
GetterSetterExample example = new GetterSetterExample();
example.setName("test");
example.setAge(20);
System.out.printf("name:%s age:%d",example.getName(),example.getAge());
}
}
編譯后Lombok會(huì)生成如下代碼。
public class GetterSetterExample {
private String name;
private Integer age;
public GetterSetterExample() {
}
public String getName() {
return this.name;
}
public void setName(final String name) {
this.name = name;
}
public Integer getAge() {
return this.age;
}
protected void setAge(final Integer age) {
this.age = age;
}
}
@ToString
把所有類(lèi)屬性都編寫(xiě)到toString方法中方便打印日志,是一件多么枯燥無(wú)味的事情。使用@ToString注解可以自動(dòng)生成toString方法,默認(rèn)會(huì)包含所有類(lèi)屬性,使用@ToString.Exclude注解可以排除屬性的生成。
/**
* Created by macro on 2020/12/17.
*/
@ToString
public class ToStringExample {
@ToString.Exclude
private Long id;
private String name;
private Integer age;
public ToStringExample(Long id,String name,Integer age){
this.id =id;
this.name = name;
this.age = age;
}
public static void main(String[] args) {
ToStringExample example = new ToStringExample(1L,"test",20);
//自動(dòng)實(shí)現(xiàn)toString方法,輸出ToStringExample(name=test, age=20)
System.out.println(example);
}
}
編譯后Lombok會(huì)生成如下代碼。
public class ToStringExample {
private Long id;
private String name;
private Integer age;
public ToStringExample(Long id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public String toString() {
return "ToStringExample(name=" + this.name + ", age=" + this.age + ")";
}
}
@EqualsAndHashCode
使用@EqualsAndHashCode注解可以自動(dòng)生成hashCode和equals方法,默認(rèn)包含所有類(lèi)屬性,使用@EqualsAndHashCode.Exclude可以排除屬性的生成。
/**
* Created by macro on 2020/12/17.
*/
@Getter
@Setter
@EqualsAndHashCode
public class EqualsAndHashCodeExample {
private Long id;
@EqualsAndHashCode.Exclude
private String name;
@EqualsAndHashCode.Exclude
private Integer age;
public static void main(String[] args) {
EqualsAndHashCodeExample example1 = new EqualsAndHashCodeExample();
example1.setId(1L);
example1.setName("test");
example1.setAge(20);
EqualsAndHashCodeExample example2 = new EqualsAndHashCodeExample();
example2.setId(1L);
//equals方法只對(duì)比id,返回true
System.out.println(example1.equals(example2));
}
}
編譯后Lombok會(huì)生成如下代碼。
public class EqualsAndHashCodeExample {
private Long id;
private String name;
private Integer age;
public EqualsAndHashCodeExample() {
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof EqualsAndHashCodeExample)) {
return false;
} else {
EqualsAndHashCodeExample other = (EqualsAndHashCodeExample)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$id = this.getId();
Object other$id = other.getId();
if (this$id == null) {
if (other$id != null) {
return false;
}
} else if (!this$id.equals(other$id)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(final Object other) {
return other instanceof EqualsAndHashCodeExample;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
return result;
}
}
@XxConstructor
使用@XxConstructor注解可以自動(dòng)生成構(gòu)造方法,有@NoArgsConstructor、@RequiredArgsConstructor和@AllArgsConstructor三個(gè)注解可以使用。
- @NoArgsConstructor:生成無(wú)參構(gòu)造函數(shù)。
- @RequiredArgsConstructor:生成包含必須參數(shù)的構(gòu)造函數(shù),使用@NonNull注解的類(lèi)屬性為必須參數(shù)。
- @AllArgsConstructor:生成包含所有參數(shù)的構(gòu)造函數(shù)。
/**
* Created by macro on 2020/12/17.
*/
@NoArgsConstructor
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor
public class ConstructorExample {
@NonNull
private Long id;
private String name;
private Integer age;
public static void main(String[] args) {
//無(wú)參構(gòu)造器
ConstructorExample example1 = new ConstructorExample();
//全部參數(shù)構(gòu)造器
ConstructorExample example2 = new ConstructorExample(1L,"test",20);
//@NonNull注解的必須參數(shù)構(gòu)造器
ConstructorExample example3 = ConstructorExample.of(1L);
}
}
編譯后Lombok會(huì)生成如下代碼。
public class ConstructorExample {
@NonNull
private Long id;
private String name;
private Integer age;
public ConstructorExample() {
}
private ConstructorExample(@NonNull final Long id) {
if (id == null) {
throw new NullPointerException("id is marked non-null but is null");
} else {
this.id = id;
}
}
public static ConstructorExample of(@NonNull final Long id) {
return new ConstructorExample(id);
}
public ConstructorExample(@NonNull final Long id, final String name, final Integer age) {
if (id == null) {
throw new NullPointerException("id is marked non-null but is null");
} else {
this.id = id;
this.name = name;
this.age = age;
}
}
}
@Data
@Data是一個(gè)方便使用的組合注解,是@ToString、@EqualsAndHashCode、@Getter、@Setter和@RequiredArgsConstructor的組合體。
/**
* Created by macro on 2020/12/17.
*/
@Data
public class DataExample {
@NonNull
private Long id;
@EqualsAndHashCode.Exclude
private String name;
@EqualsAndHashCode.Exclude
private Integer age;
public static void main(String[] args) {
//@RequiredArgsConstructor已生效
DataExample example1 = new DataExample(1L);
//@Getter @Setter已生效
example1.setName("test");
example1.setAge(20);
//@ToString已生效
System.out.println(example1);
DataExample example2 = new DataExample(1L);
//@EqualsAndHashCode已生效
System.out.println(example1.equals(example2));
}
}
編譯后Lombok會(huì)生成如下代碼。
public class DataExample {
@NonNull
private Long id;
private String name;
private Integer age;
public DataExample(@NonNull final Long id) {
if (id == null) {
throw new NullPointerException("id is marked non-null but is null");
} else {
this.id = id;
}
}
@NonNull
public Long getId() {
return this.id;
}
public String getName() {
return this.name;
}
public Integer getAge() {
return this.age;
}
public void setId(@NonNull final Long id) {
if (id == null) {
throw new NullPointerException("id is marked non-null but is null");
} else {
this.id = id;
}
}
public void setName(final String name) {
this.name = name;
}
public void setAge(final Integer age) {
this.age = age;
}
public boolean equals(final Object o) {
if (o == this) {
return true;
} else if (!(o instanceof DataExample)) {
return false;
} else {
DataExample other = (DataExample)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$id = this.getId();
Object other$id = other.getId();
if (this$id == null) {
if (other$id != null) {
return false;
}
} else if (!this$id.equals(other$id)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(final Object other) {
return other instanceof DataExample;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
return result;
}
public String toString() {
return "DataExample(id=" + this.getId() + ", name=" + this.getName() + ", age=" + this.getAge() + ")";
}
}
@Value
使用@Value注解可以把類(lèi)聲明為不可變的,聲明后此類(lèi)相當(dāng)于final類(lèi),無(wú)法被繼承,其屬性也會(huì)變成final屬性。
/**
* Created by macro on 2020/12/17.
*/
@Value
public class ValueExample {
private Long id;
private String name;
private Integer age;
public static void main(String[] args) {
//只能使用全參構(gòu)造器
ValueExample example = new ValueExample(1L,"test",20);
// example.setName("andy") //沒(méi)有生成setter方法,會(huì)報(bào)錯(cuò)
// example.name="andy" //字段被設(shè)置為final類(lèi)型,會(huì)報(bào)錯(cuò)
}
}
編譯后Lombok會(huì)生成如下代碼。
public final class ValueExample {
private final Long id;
private final String name;
private final Integer age;
public static void main(String[] args) {
new ValueExample(1L, "test", 20);
}
public ValueExample(final Long id, final String name, final Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Long getId() {
return this.id;
}
public String getName() {
return this.name;
}
public Integer getAge() {
return this.age;
}
}
@Builder
使用@Builder注解可以通過(guò)建造者模式來(lái)創(chuàng)建對(duì)象,建造者模式加鏈?zhǔn)秸{(diào)用,創(chuàng)建對(duì)象太方便了!
/**
* Created by macro on 2020/12/17.
*/
@Builder
@ToString
public class BuilderExample {
private Long id;
private String name;
private Integer age;
public static void main(String[] args) {
BuilderExample example = BuilderExample.builder()
.id(1L)
.name("test")
.age(20)
.build();
System.out.println(example);
}
}
編譯后Lombok會(huì)生成如下代碼。
public class BuilderExample {
private Long id;
private String name;
private Integer age;
BuilderExample(final Long id, final String name, final Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public static BuilderExample.BuilderExampleBuilder builder() {
return new BuilderExample.BuilderExampleBuilder();
}
public String toString() {
return "BuilderExample(id=" + this.id + ", name=" + this.name + ", age=" + this.age + ")";
}
public static class BuilderExampleBuilder {
private Long id;
private String name;
private Integer age;
BuilderExampleBuilder() {
}
public BuilderExample.BuilderExampleBuilder id(final Long id) {
this.id = id;
return this;
}
public BuilderExample.BuilderExampleBuilder name(final String name) {
this.name = name;
return this;
}
public BuilderExample.BuilderExampleBuilder age(final Integer age) {
this.age = age;
return this;
}
public BuilderExample build() {
return new BuilderExample(this.id, this.name, this.age);
}
public String toString() {
return "BuilderExample.BuilderExampleBuilder(id=" + this.id + ", name=" + this.name + ", age=" + this.age + ")";
}
}
}
@SneakyThrows
還在手動(dòng)捕獲并拋出異常?使用@SneakyThrows注解自動(dòng)實(shí)現(xiàn)試試!
/**
* Created by macro on 2020/12/17.
*/
public class SneakyThrowsExample {
//自動(dòng)拋出異常,無(wú)需處理
@SneakyThrows(UnsupportedEncodingException.class)
public static byte[] str2byte(String str){
return str.getBytes("UTF-8");
}
public static void main(String[] args) {
String str = "Hello World!";
System.out.println(str2byte(str).length);
}
}
編譯后Lombok會(huì)生成如下代碼。
public class SneakyThrowsExample {
public SneakyThrowsExample() {
}
public static byte[] str2byte(String str) {
try {
return str.getBytes("UTF-8");
} catch (UnsupportedEncodingException var2) {
throw var2;
}
}
}
@Synchronized
當(dāng)我們?cè)诙鄠€(gè)線程中訪問(wèn)同一資源時(shí),往往會(huì)出現(xiàn)線程安全問(wèn)題,以前我們往往使用synchronized關(guān)鍵字修飾方法來(lái)實(shí)現(xiàn)同步訪問(wèn)。使用@Synchronized注解同樣可以實(shí)現(xiàn)同步訪問(wèn)。
package com.macro.mall.tiny.example;
import lombok.*;
/**
* Created by macro on 2020/12/17.
*/
@Data
public class SynchronizedExample {
@NonNull
private Integer count;
@Synchronized
@SneakyThrows
public void reduceCount(Integer id) {
if (count > 0) {
Thread.sleep(500);
count--;
System.out.println(String.format("thread-%d count:%d", id, count));
}
}
public static void main(String[] args) {
//添加@Synchronized三個(gè)線程可以同步調(diào)用reduceCount方法
SynchronizedExample example = new SynchronizedExample(20);
new ReduceThread(1, example).start();
new ReduceThread(2, example).start();
new ReduceThread(3, example).start();
}
@RequiredArgsConstructor
static class ReduceThread extends Thread {
@NonNull
private Integer id;
@NonNull
private SynchronizedExample example;
@Override
public void run() {
while (example.getCount() > 0) {
example.reduceCount(id);
}
}
}
}
編譯后Lombok會(huì)生成如下代碼。
public class SynchronizedExample {
private final Object $lock = new Object[0];
@NonNull
private Integer count;
public void reduceCount(Integer id) {
try {
synchronized(this.$lock) {
if (this.count > 0) {
Thread.sleep(500L);
Integer var3 = this.count;
Integer var4 = this.count = this.count - 1;
System.out.println(String.format("thread-%d count:%d", id, this.count));
}
}
} catch (Throwable var7) {
throw var7;
}
}
}
@With
使用@With注解可以實(shí)現(xiàn)對(duì)原對(duì)象進(jìn)行克隆,并改變其一個(gè)屬性,使用時(shí)需要指定全參構(gòu)造方法。
@With
@AllArgsConstructor
public class WithExample {
private Long id;
private String name;
private Integer age;
public static void main(String[] args) {
WithExample example1 = new WithExample(1L, "test", 20);
WithExample example2 = example1.withAge(22);
//將原對(duì)象進(jìn)行clone并設(shè)置age,返回false
System.out.println(example1.equals(example2));
}
}
編譯后Lombok會(huì)生成如下代碼。
public class WithExample {
private Long id;
private String name;
private Integer age;
public WithExample withId(final Long id) {
return this.id == id ? this : new WithExample(id, this.name, this.age);
}
public WithExample withName(final String name) {
return this.name == name ? this : new WithExample(this.id, name, this.age);
}
public WithExample withAge(final Integer age) {
return this.age == age ? this : new WithExample(this.id, this.name, age);
}
public WithExample(final Long id, final String name, final Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
}
@Getter(lazy=true)
當(dāng)我們獲取某一個(gè)屬性比較消耗資源時(shí),可以給@Getter添加 lazy=true 屬性實(shí)現(xiàn)懶加載,會(huì)生成Double Check Lock 樣板代碼對(duì)屬性進(jìn)行懶加載。
/**
* Created by macro on 2020/12/17.
*/
public class GetterLazyExample {
@Getter(lazy = true)
private final double[] cached = expensive();
private double[] expensive() {
double[] result = new double[1000000];
for (int i = 0; i < result.length; i++) {
result[i] = Math.asin(i);
}
return result;
}
public static void main(String[] args) {
//使用Double Check Lock 樣板代碼對(duì)屬性進(jìn)行懶加載
GetterLazyExample example = new GetterLazyExample();
System.out.println(example.getCached().length);
}
}
編譯后Lombok會(huì)生成如下代碼。
public class GetterLazyExample {
private final AtomicReference<Object> cached = new AtomicReference();
public GetterLazyExample() {
}
private double[] expensive() {
double[] result = new double[1000000];
for(int i = 0; i < result.length; ++i) {
result[i] = Math.asin((double)i);
}
return result;
}
public double[] getCached() {
Object value = this.cached.get();
if (value == null) {
synchronized(this.cached) {
value = this.cached.get();
if (value == null) {
double[] actualValue = this.expensive();
value = actualValue == null ? this.cached : actualValue;
this.cached.set(value);
}
}
}
return (double[])((double[])(value == this.cached ? null : value));
}
}
@Log
使用@Log注解,可以直接生成日志對(duì)象log,通過(guò)log對(duì)象可以直接打印日志。
/**
* Created by macro on 2020/12/17.
*/
@Log
public class LogExample {
public static void main(String[] args) {
log.info("level info");
log.warning("level warning");
log.severe("level severe");
}
}
編譯后Lombok會(huì)生成如下代碼。
public class LogExample {
private static final Logger log = Logger.getLogger(LogExample.class.getName());
public LogExample() {
}
public static void main(String[] args) {
log.info("level info");
log.warning("level warning");
log.severe("level severe");
}
}
@Slf4j
使用Lombok生成日志對(duì)象時(shí),根據(jù)使用日志實(shí)現(xiàn)的不同,有多種注解可以使用。比如@Log、@Log4j、@Log4j2、@Slf4j等。
/**
* Created by macro on 2020/12/17.
*/
@Slf4j
public class LogSlf4jExample {
public static void main(String[] args) {
log.info("level:{}","info");
log.warn("level:{}","warn");
log.error("level:{}", "error");
}
}
編譯后Lombok會(huì)生成如下代碼。
public class LogSlf4jExample {
private static final Logger log = LoggerFactory.getLogger(LogSlf4jExample.class);
public LogSlf4jExample() {
}
public static void main(String[] args) {
log.info("level:{}", "info");
log.warn("level:{}", "warn");
log.error("level:{}", "error");
}
}
Lombok原理
如果IDEA不安裝Lombok插件的話,我們打開(kāi)使用Lombok的項(xiàng)目是無(wú)法通過(guò)編譯的。裝了以后IDEA才會(huì)提示我們Lombok為我們生成的方法和屬性。
使用了@Data注解以后,查看類(lèi)結(jié)構(gòu)可以發(fā)現(xiàn)getter、setter、toString等方法。

打開(kāi)target目錄下的 .class 文件,我們可以看到Lombok為我們生成的代碼,可見(jiàn)Lombok是通過(guò)解析注解,然后在編譯時(shí)生成代碼來(lái)實(shí)現(xiàn)Java代碼的功能增強(qiáng)的。
參考資料
官方文檔:https://projectlombok.org/features/all
項(xiàng)目源碼地址
https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-lombok
到此這篇關(guān)于Lombok為啥這么牛逼?SpringBoot和IDEA官方都要支持它的文章就介紹到這了,更多相關(guān)Lombok SpringBoot和IDEA內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Lombok插件有望被Intellij IDEA收編以改善兼容性問(wèn)題(推薦)
- Lombok插件安裝(IDEA)及配置jar包使用詳解
- 關(guān)于idea2020.3升級(jí)lombok不能使用的問(wèn)題
- 解決IDEA 2020.3 lombok失效問(wèn)題
- 升級(jí)IDEA后Lombok不能使用的解決方法
- idea 在springboot中使用lombok插件的方法
- idea中l(wèi)ombok的用法
- idea中的lombok不生效的四種解決方法
- IDEA編寫(xiě)SpringBoot項(xiàng)目時(shí)使用Lombok報(bào)錯(cuò)“找不到符號(hào)”的原因和解決
相關(guān)文章
SpringBoot?Aop實(shí)現(xiàn)接口請(qǐng)求次數(shù)統(tǒng)計(jì)
我們通過(guò)Spring AOP在每次執(zhí)行方法前或執(zhí)行方法后進(jìn)行切面的處理,進(jìn)而統(tǒng)計(jì)方法訪問(wèn)的次數(shù)等功能,本文主要介紹了SpringBoot?Aop實(shí)現(xiàn)接口請(qǐng)求次數(shù)統(tǒng)計(jì)2024-02-02
關(guān)于@ConfigurationProperties注解全解析
通過(guò)@ConfigurationProperties和@ConditionalOnProperty注解,可以實(shí)現(xiàn)基于配置的條件加載Bean,以此優(yōu)化Spring Boot應(yīng)用的啟動(dòng)速度,在application.yml中設(shè)置配置項(xiàng),如是否加載特定的Bean(以swagger配置為例)2024-11-11
IKAnalyzer結(jié)合Lucene實(shí)現(xiàn)中文分詞(示例講解)
下面小編就為大家?guī)?lái)一篇IKAnalyzer結(jié)合Lucene實(shí)現(xiàn)中文分詞(示例講解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
Springboot引入攔截器并放行swagger代碼實(shí)例
這篇文章主要介紹了Springboot引入攔截器并放行swagger代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
spring boot項(xiàng)目fat jar瘦身的實(shí)現(xiàn)
這篇文章主要介紹了spring boot項(xiàng)目fat jar瘦身的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
RestTemplate 401 獲取錯(cuò)誤信息的處理方案
這篇文章主要介紹了RestTemplate 401 獲取錯(cuò)誤信息的處理方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
springcloud如何獲取網(wǎng)關(guān)封裝的頭部信息
這篇文章主要介紹了springcloud獲取網(wǎng)關(guān)封裝的頭部信息,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
Spring Boot集成Thymeleaf模板引擎的完整步驟
這篇文章主要給大家介紹了關(guān)于Spring Boot集成Thymeleaf模板引擎的完整步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02

