1. 前言

欢迎加入[​微信圈子​]程序员交流圈 交流编程经验。

随着我们项目的不断迭代 ​Bean​ 的数量会大大增加,如果都在启动时进行初始化会非常耗时。​Spring Boot​ 允许延迟初始化应用程序, 也就是根据需要初始化 ​Spring Bean​,而不是在 ​Spring Boot​ 启动时创建所有的 ​Bean​。这样的就可以减少应用程序启动花费的时间。延迟初始化通常又被称为“懒加载”。

2. 延迟初始化

Spring Boot​ 中的延迟初始化可分为​全局延迟初始化​和​局部初始化

2.1 全局初始化

全局初始化我们可以通过编程的方式来实现,需要我们来改变 ​Spring Boot Main​方法的写法。

通常我们的 ​Main​ 方法是这样的,​注意这里还没声明全局懒加载

/**
* @author felord.cn
* @since 2020/3/31 22:53
*/
@SpringBootApplication
public class DemoSpringbootApplication {
@Lazy
public static void main(String[] args) {
SpringApplication.run(DemoSpringbootApplication.class,args);
}
}

全局懒加载写法一:

/**
* @author felord.cn
* @since 2020/3/31 22:53
*/
@SpringBootApplication
public class DemoSpringbootApplication {
@Lazy
public static void main(String[] args) {
SpringApplication sa = new SpringApplication(DemoSpringbootApplication.class);

sa.setLazyInitialization(true);
sa.run(args);
}
}

全局懒加载写法二:

/**
* @author felord.cn
* @since 2020/3/31 22:53
*/
@SpringBootApplication
public class DemoSpringbootApplication {
@Lazy
public static void main(String[] args) {
SpringApplicationBuilder sab = new SpringApplicationBuilder(DemoSpringbootApplication.class);

sab.lazyInitialization(true).run(args);
}
}

上面的写法一和写法二都是我们通过编程方式定制一些 ​Spring Boot​ 特性,大多数都是全局特性。包括本文讲述的 “懒加载”。

我们还可以采取更简单的配置文件(​application.properties​)的方式来配置延迟初始化:

# 默认是关闭的 false
spring.main.lazy-initialization=true

当我们开启了全局的延迟加载后,在 ​Web​ 应用程序中将导致许多与 ​Web​ 相关的 ​Bean​ 直到收到第一次 ​HTTP​ 请求后才被初始化。

控制器

/**
* @author felord.cn
* @since 2020/3/31 23:31
*/
@RestController
@RequestMapping
public class FooController {
private FooService fooService;

public FooController(FooService fooService) {
this.fooService = fooService;
}

@GetMapping("/req")
public Map<String, String> demo() {
System.out.println("Preparing HTTP request...");
return fooService.response();
}

}

服务层

/**
* @author felord.cn
* @since 2020/3/31 23:36
*/
@Service
public class FooService {
public FooService() {
System.out.println("fooService init ...");
}

public Map<String, String> response() {
Map<String, String> map = new HashMap<>();
map.put("msg","from fooService");
return map;
}
}

调用 ​​/req​​​ 接口后我们发现,不单单 ​​FooController​​​ 和 ​​FooService​​ 在第一次调用初始化,连 ​Spring MVC​ 核心过滤器 ​​DispatcherServlet​​ 都是第一次调用时初始化。


合理利用延迟初始化优化 Spring Boot_spring

2.2 局部初始化

如果我们不想让全局延迟初始化作用于个别的 ​Bean​ 怎么办?我们可以在这个 ​Bean​ 上声明注解 ​​@Lazy(value = false)​​ 即可。你可以改写 ​2.1​ 的代码自己试一试。这个 ​​@Lazy​​​ 作用于局部,并通过布尔值 ​​value​​ 来控制是否延迟初始化。情况是这样的:

  • 当我们声明全局延迟加载时,​​@Lazy(value = false)​​标记的 ​Bean​ 会被立即加载。

  • 当我们声明全局​​延迟加载时,​​@Lazy​​ 标记的 ​Bean​ 会被延迟加载。


请注意:​​@Lazy​​​ 会影响到 ​​@Configuration​​ 下声明的 ​Bean


3. 注意事项

延迟初始化的缺点是,如果错误配置的 ​Bean​ 是延迟初始化的,则在启动期间将不再发生故障,并且只有在初始化 ​Bean​ 时错误才会暴露出来,所以一定要经过严格的测试。

同时还必须注意确保 ​JVM​ 具有足够的内存来容纳所有应用程序的 ​Bean​,而不仅仅是启动期间初始化的 ​Bean​。因此建议在启用延迟初始化之前先对 ​JVM​ 的堆大小进行必要的检测和微调以保证不会溢出。

那些初始化耗时,具有复杂逻辑,而且不是启动的必要选择的 ​Bean​ 应当被延迟初始化。

4. 总结

今天对 ​Spring Boot​ 如何进行延迟初始化进行了讲解,同时也说明了一些注意事项。间接地也对 ​Main​ 方法的几种姿势也进行了展示,希望对你的实际开发有所帮助。关注公众号:​Felordcn​ 将自动获取技术干货资料。

合理利用延迟初始化优化 Spring Boot_编程语言_02


合理利用延迟初始化优化 Spring Boot_spring boot_03