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 注解。