Spring Boot @Lazy
上次修改时间:2023 年 7 月 23 日
在本文中,我们将展示如何使用 Spring 的 @Lazy 注解进行懒加载 Bean 初始化。
Spring 是一个流行的 Java 应用程序框架,用于创建企业应用程序。Spring Boot 是 Spring 框架的演进,它有助于以最小的 effort 创建基于 Spring 的独立、生产级应用程序。
@Lazy
@Lazy
注解指示是否懒加载一个 Bean。它可以在 @Component
和 @Bean
定义中使用。一个 @Lazy
Bean 在被另一个 Bean 引用或从 BeanFactory
显式检索之前不会被初始化。未用 @Lazy
注解的 Bean 将被急切地初始化。
Spring Boot @Lazy 示例
在下面的示例中,我们创建了懒加载和急切加载的 Bean。它演示了这两种类型的 Bean 之间的区别。该应用程序是一个简单的 Spring Boot Web 应用程序,在嵌入式 Tomcat 服务器上运行。我们使用 Freemarker 模板引擎。
build.gradle ... src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ ├── Application.java │ │ ├── bean │ │ │ ├── MyBean.java │ │ │ ├── MyLazyBean.java │ │ │ └── StartUpBean.java │ │ └── controller │ │ └── MyController.java │ └── resources │ ├── application.properties │ ├── static │ │ └── index.html │ └── templates │ └── showMessages.ftlh └── test └── java
这是项目结构。
plugins { id 'org.springframework.boot' version '3.1.1' id 'io.spring.dependency-management' version '1.1.0' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-freemarker' }
这是 build.gradle
文件。
spring.main.banner-mode=off logging.level.org.springframework=ERROR
在 application.properties
中,我们关闭了启动横幅并设置了日志级别。
package com.zetcode.bean; import org.springframework.stereotype.Component; import java.util.logging.Logger; @Component public class MyBean { static Logger log = Logger.getLogger(MyBean.class.getName()); public MyBean() { log.info("MyBean initialized"); } public String getMessage() { return "Message from MyBean"; } }
这是 MyBean
。该 Bean 被急切地初始化,即在 Spring 框架启动时。
package com.zetcode.bean; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import java.util.logging.Logger; @Component @Lazy public class MyLazyBean { static Logger log = Logger.getLogger(MyLazyBean.class.getName()); public MyLazyBean() { log.info("MyLazyBean initialized"); } public String getMessage() { return "Message from MyLazyBean"; } }
MyLazyBean
包含 @Lazy
注解。它在第一次被请求时进行懒加载。它从控制器中被请求。
package com.zetcode.bean; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import java.util.logging.Logger; @Component public class StartUpBean implements ApplicationListener<ApplicationReadyEvent> { static Logger log = Logger.getLogger(StartUpBean.class.getName()); @Override public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { log.info("Application is ready"); } }
StartUpBean
实现了一个应用程序监听器;当应用程序准备就绪时,它会记录一条消息。
package com.zetcode.controller; import com.zetcode.bean.MyBean; import com.zetcode.bean.MyLazyBean; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller public class MyController { private final BeanFactory factory; @Autowired public MyController(BeanFactory factory) { this.factory = factory; } @GetMapping(path="/messages") public String getMessages(Model model) { MyLazyBean myLazyBean = factory.getBean(MyLazyBean.class); MyBean myBean = factory.getBean(MyBean.class); model.addAttribute("mybean", myBean.getMessage()); model.addAttribute("mylazybean", myLazyBean.getMessage()); return "showMessages"; } }
这是一个控制器类。它创建了两个 Bean 并接收它们的消息。这些消息显示在 Freemarker 模板中。
private final BeanFactory factory; @Autowired public MyController(BeanFactory factory) { this.factory = factory; }
我们注入了 BeanFactory
。该工厂用于访问 Spring Bean。
MyLazyBean myLazyBean = factory.getBean(MyLazyBean.class);
这是 MyLazyBean
被初始化的时刻。
MyBean myBean = factory.getBean(MyBean.class);
我们从工厂中获取 MyBean
;MyBean
在 Spring 启动时被初始化。
<!DOCTYPE html> <html> <head> <title>Show data</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <p> MyBean: ${mybean} </p> <p> MyLazyBean: ${mylazybean} </p> </body> </html>
Freemarker 模板显示来自两个 Bean 的消息。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Home page</title> </head> <body> <a href="messages">Get messages</a> </body> </html>
在 index.html
中有一个链接可以获取来自 Bean 的消息。
package com.zetcode; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Application
设置了 Spring Boot 应用程序。@SpringBootApplication
启用了自动配置和组件扫描。
$ ./gradlew bootRun
我们启动应用程序。
Initializing Spring embedded WebApplicationContext com.zetcode.bean.MyBean : MyBean initialized com.zetcode.Application : Started Application in 2.483 seconds (JVM running for 2.854) com.zetcode.bean.StartUpBean : Application is ready
当 Spring Boot 启动时,我们可以看到这些日志消息。请注意,MyBean
在启动时被初始化。
com.zetcode.bean.MyLazyBean : MyLazyBean initialized
当控制器被调用时,MyLazyBean
被初始化。
在本文中,我们展示了如何使用 Spring @Lazy
注解。