為什么需要懶加載?
我們知道,在 SpringBoot 應(yīng)用程序啟動的時候,會實(shí)例化一些對象加入到 IOC 容器里邊,這個過程是非常耗時的,那我們想要減少這個耗時的過程就需要 @Lazy 注解
對象加入容器的時機(jī)
如下代碼
package com.startdusk.forgot.service;
import org.springframework.stereotype.Component;
@Service
public class LazyService {
public LazyService() {
System.out.println("LazyService add to ioc container");
}
public void print() {
System.out.println("lazy");
}
}
由于我們在 LazyService 中打上了 @Service 注解,那么當(dāng)程序啟動的時候,LazyService 就會被立即實(shí)例化,我們在 LazyService 寫了個無參的構(gòu)造函數(shù)來測試,啟動程序,會打印出

那么說明,在打上了 @Service 注解后,在程序啟動的時候就立即實(shí)例化對象加入到容器
使用 @Lazy 延遲加入容器
那我們來改寫下代碼,延遲加入容器:
package com.startdusk.forgot.service;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@Service
@Lazy
public class LazyService {
public LazyService() {
System.out.println("LazyService add to ioc container");
}
public void print() {
System.out.println("lazy");
}
}
再來運(yùn)行一下程序:

看到運(yùn)行的結(jié)果,并沒有打印 "LazyService add to ioc container" 也就沒有實(shí)例化 LazyService ,說明 @Lazy 注解起作用了,我們延遲了對象加入容器的時機(jī)
一個奇怪的現(xiàn)象
那么在實(shí)際情況中,我們會在 controller 中調(diào)用這個 service,即在 controller 中注入這個對象:
package com.startdusk.forgot.api.v1;
import com.startdusk.forgot.service.LazyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/v1/lazy")
public class LazyController {
@Autowired
private LazyService lazyService;
@GetMapping("/test")
public String test() {
lazyService.print();
return "Hello, world";
}
}
保持 LazyService 中的 @Lazy,我們運(yùn)行程序

發(fā)現(xiàn) LazyService 居然被實(shí)例化了,難道打上 @Lazy 注解的類被注入之后 @Lazy 就不起作用了嗎?我們來看下這個 LazyController 的代碼,這里其實(shí)我們也把 LazyController 加入了容器(即打上了 @RestController 注解),在 SpringBoot 中,加入 IOC 容器就必須實(shí)例化對象,而實(shí)例化對象就要求,這個對象的里面的成員變量,方法都要被初始化,就包括 lazyService 這個要被注入的變量,即使 LazyService 打上了 @Lazy 注解。
解決這個問題,我們也需要在 LazyController 打上 @Lazy 注解,才能延遲加入 IOC 容器
package com.startdusk.forgot.api.v1;
import com.startdusk.forgot.service.LazyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/v1/lazy")
@Lazy
public class LazyController {
@Autowired
private LazyService lazyService;
@GetMapping("/test")
public String test() {
lazyService.print();
return "Hello, world";
}
}
@Lazy 會延遲到什么時候
會延遲到對象被調(diào)用的時候。如,運(yùn)行程序,訪問 localhost:8080/v1/lazy/test 就是訪問 test 這個方法,那么就會調(diào)用 lazyService.print() 就會打印出:

我們可以看到,當(dāng)被注入的對象被調(diào)用的時候,才會把對象加入 IOC 容器,然后注入對象
使用 @Lazy 的缺點(diǎn)
我們來調(diào)整下代碼:
LazyService 注釋掉 @Service 和 @Lazy
package com.startdusk.forgot.service;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
// @Service
// @Lazy
public class LazyService {
public LazyService() {
System.out.println("LazyService add to ioc container");
}
public void print() {
System.out.println("lazy");
}
}
那么運(yùn)行代碼,再來訪問下 localhost:8080/v1/lazy/test
,那么,程序會給我們拋一個錯誤:
Error creating bean with name 'lazyController': Unsatisfied dependency expressed through field 'lazyService';......
就是找不到這個這個注入的對象。那么這個報錯是在程序運(yùn)行中報錯,而不是程序啟動的時候就報錯了。那么我們在 LazyController 中去掉 @Lazy
package com.startdusk.forgot.api.v1;
import com.startdusk.forgot.service.LazyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/v1/lazy")
public class LazyController {
@Autowired
private LazyService lazyService;
@GetMapping("/test")
public String test() {
lazyService.print();
return "Hello, world";
}
}
啟動程序,那么就會在程序啟動的時候直接報錯,不讓你運(yùn)行
Field lazyService in com.startdusk.forgot.api.v1.LazyController required a bean of type 'com.startdusk.forgot.service.LazyService' that could not be found.