合理利用延迟初始化优化 Spring Boot
发布日期:2021-06-29 21:46:58 浏览次数:2 分类:技术文章

本文共 2857 字,大约阅读时间需要 9 分钟。

点击上方蓝色“程序猿DD”,选择“设为星标”

回复“资源”获取独家整理的学习资料!

来源 | 公众号「码农小胖哥」

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 */@SpringBootApplicationpublicclass DemoSpringbootApplication {    @Lazy    public static void main(String[] args) {        SpringApplication.run(DemoSpringbootApplication.class,args);    }}

全局懒加载写法一:

/** * @author felord.cn * @since 2020/3/31 22:53 */@SpringBootApplicationpublicclass 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 */@SpringBootApplicationpublicclass DemoSpringbootApplication {    @Lazy    public static void main(String[] args) {       SpringApplicationBuilder sab = new SpringApplicationBuilder(DemoSpringbootApplication.class);        sab.lazyInitialization(true).run(args);    }}

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

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

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

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

控制器

/** * @author felord.cn * @since 2020/3/31 23:31 */@RestController@RequestMappingpublicclass FooController {    private FooService fooService;    public FooController(FooService fooService) {        this.fooService = fooService;    }    @GetMapping("/req")    public Map
demo() { System.out.println("Preparing HTTP request..."); return fooService.response(); }}

服务层

/** * @author felord.cn * @since 2020/3/31 23:36 */@Servicepublicclass FooService {    public FooService() {        System.out.println("fooService init ...");    }    public Map
response() { Map
map = new HashMap<>(); map.put("msg","from fooService"); return map; }}

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

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 应当被延迟初始化。

推荐关注本文作者

勤奋高产的码农小胖哥

转载地址:https://didispace-wx.blog.csdn.net/article/details/105336786 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:盘点:35 个 Java 代码优化魔鬼细节
下一篇:这四个问题场景你会排查原因吗?看看高手是如何使用 Arthas 快速定位原因的!...

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年04月24日 19时56分23秒