使用lazyInit缩短Spring Boot启动时间

18-08-19 banq
         

虽然Spring Boot DevTools提供的快速重启有助于库类加载,但并不能解决Spring Boot应用启动时间长的问题。在本文中,我们将看看如何使用SpringBoot的懒加载属性提升我们应用程序的启动时间。

起初,无论你选择哪种嵌入式服务器Tomcat或Jetty,全新轻装上阵的Spring Boot Web应用都会快速启动。随着新功能和依赖项不断加入,应用程变得越来越重,启动时间也越来越长。从建立与数据库的连接,通过网络从集成端点获取数据,或从本地资源加载以及解析50兆字节的XML文件,你的应用在启动后就非常繁忙,有时超过十几分钟或更长时间。

所有繁重工作在都放在启动时完成,这样应用在运行时能有很好的性能,用户操作我们的应用时就无需停顿等待或遇到糟糕的性能,所有资源都已准备好并进行缓存,因此在真正请求时可立即使用。

另一方面,作为开发人员,我们也不喜欢等待并浪费时间对启动日志进行非生产性检查。这里有一个简单的解决方案可以应用于任何项目,以减轻一些等待启动的痛苦并改善你的开发体验。

想象一下,如果你有一个Spring bean来加载和缓存某些资源的值,资源可能是远程Web服务或需要映射到模型对象的本地CSV文件的数组,在生产环境中,在启动时需要做这样事情。

但是,如果你在本地运行应用程序,则很可能并不总是需要此资源,而只是在使用依赖于它的功能时才需要此资源。在下面的示例中,我们使用sleep()方法人为代表应用的缓慢启动。

@Component
class ResourceLoader {
 
    private List<Term> resources;
 
    @PostConstruct
    void initHeavyLoading() throws InterruptedException {
        log.info("Loading start");
        // time-consuming execution
        Thread.sleep(10_000);
        resources = loadResources();
        log.info("Loading end");
    }
     
    // …
 
}
<p>

Spring Boot可以进行有助于相关针对项目的设置,包括最常见的默认设置和随时可用的配置,这无疑是很棒的,因为它节省了宝贵的时间 然而,对于框架的新手来说,可能不熟悉这些配置。

你可能知道@SpringBootApplication本身并没有做任何事情。它默认组合三个注释@Configuration,@EnableAutoConfiguration和@ComponentScan,但是,并不是每个人都知道@ComponentScan注释有一个特别有用的属性: lazyInit。

LazyInit是一个布尔标志,指示容器在启动时或第一次访问容器时是否应该立即地创建所有发现的bean。默认情况下,该标志设置为false,这在生产中很好,但在本地计算机上开发应用程序时不一定。

我们想要实现的是仅在本地开发环境中启用bean延迟加载,并在生产环境实现立即初始化加载。

 
@SpringBootApplication
public class LazyApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(LazyApplication.class, args);
    }
 
    @Configuration
    @Profile("local")
    @ComponentScan(lazyInit = true)
    static class LocalConfig {
    }
 
}
<p>

上面的示例提供了一个普通的Spring Boot主入口应用类,它包含一个静态内部配置类,其中惰性初始化设置为true。该类使用@Profile进行注释,以便仅在启用本地配置文件时才激活它。

原理很简单,如果激活了本地配置文件,则LocalConfig类中@ComponentScan中的lazyInit将覆盖主类上@SpringBootApplication批注提供的默认值。如果取消激活本地配置文件,则忽略LocalConfig类并使用默认值。

最后,你需要激活计算机上的本地配置文件,有几个选项可供选择。最简单的方法是在你的操作系统中永久设置spring.profiles.active环境变量,或者在每次启动应用程序之前用你喜欢的IDE自动设置。在IntelliJ中,可以在项目主类的Run / Debug配置中指定它。

或者,如果你有一个用于本地开发的单独Maven配置文件,并且你使用Spring Boot Maven插件来运行你的应用程序,则可以在pom.xml中配置活动配置文件。

你可以在GitHub存储库中测试示例项目的功能。首先,运行没有本地配置文件的应用程序,以查看是否执行了ResourceLoader类的初始化。然后设置配置文件并重新启动应用程序。

禁用所选bean的延迟初始化

尽管@ComponentScan(lazyInit = true)会影响所有已扫描的bean,但你可以仅针对所选组件覆盖此行为并立即初始化它们。该@Lazy注释具有几个不同的用途,可以应用于互补的景或替代解决方案。如果你有兴趣在提高你的Spring应用程序的启动速度,你一定要熟悉与@Lazy注释。

了解你的工具集

在你使用JRebel之类的商业运行时字节代码操作工具之前,有必要验证简单的延迟初始化是否不足以在开发环境中提高工作舒适度。Spring是一个高度精心设计的框架,它仍在不断发展。毫不奇怪,不了解一些有用的功能是常有的事。

虽然有些人可能会认为对框架内部的熟悉与一般使用框架的想法相矛盾,但这篇文章表明,至少学习基础知识可能是有益的。

Faster Spring Boot startup | Java & Web developmen

[该贴被banq于2018-08-19 08:50修改过]