SpringBoot:使用 @Lazy 注解懶加載

為什么需要懶加載?

我們知道,在 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.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容