java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot启动优化

SpringBoot启动慢的5个优化技巧分享

作者:帅气的你

这篇文章主要为大家详细介绍了SpringBoot启动慢的5个优化技巧,本文主要针对的是 1.4/1.5 老版本,希望可以手把手教你把启动时间缩短 50%+

引言:还在等 Spring Boot 启动?可能是你没优化对

很多团队的核心业务系统还在使用 Spring Boot 1.4/1.5 这类早期经典版本:

实际排查下来,大部分启动慢问题,并不是业务逻辑本身慢,而是:

本文结合老项目实战经验,总结了 5 个几乎“零重构”的优化点

一、优化点 1:禁用不必要的自动配置(核心)

1.1 问题原因

在 Spring Boot 1.4/1.5 中,spring-boot-autoconfigure 会根据类路径和配置自动装配大量组件,比如:

问题在于:只要依赖在类路径上,Spring Boot 就会尝试自动配置 Bean
即使你项目中完全没用到这些功能,也会:

最终结果:启动阶段 Bean 初始化数量暴增,耗时显著上升

1.2 操作步骤:通过exclude精准禁用无用自动配置

步骤 1:打开 debug 日志,查看生效的自动配置

application.properties 中增加:

debug=true

启动后控制台会输出类似:

=========================
AUTO-CONFIGURATION REPORT
=========================

Positive matches:
   DataSourceAutoConfiguration matched ...
   RedisAutoConfiguration matched ...
   MailSenderAutoConfiguration matched ...
   ...

Positive matches 部分就是当前真正生效的自动配置列表。结合业务实际,挑出确定 完全不用 的配置类。

步骤 2:使用@SpringBootApplication(exclude = …)排除

在主启动类上排除这些自动配置,例如:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;

@SpringBootApplication(
    exclude = {
        DataSourceAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class,
        RedisAutoConfiguration.class,
        MailSenderAutoConfiguration.class
    }
)
public class LegacyApplication {

    public static void main(String[] args) {
        SpringApplication.run(LegacyApplication.class, args);
    }
}

如果你只在某些 profile 下需要这些配置,也可以配合 @ConditionalOnProperty 等方式做更细粒度控制,这里先给出最直接的方式。

1.3 原理说明

Spring Boot 启动过程中的大头工作包括:

通过 exclude 排除无用自动配置:

1.4 注意事项

注意:排除前必须确认业务确实不依赖该组件

如果误排除正在使用的数据源、事务或缓存相关自动配置,可能出现启动失败或运行时异常

生产环境中建议先在测试环境验证:

二、优化点 2:缩小包扫描范围

2.1 问题原因

Spring Boot 默认会:

大型老项目中,经常出现这种情况:

结果是:类路径扫描和 Bean 定义解析工作量明显增大,启动开销增加。

2.2 操作步骤:精确指定需要扫描的业务包

步骤 1:使用scanBasePackages明确核心业务包

在主启动类中指定扫描范围,例如:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(
    scanBasePackages = {
        "com.company.project.api",
        "com.company.project.service",
        "com.company.project.repository",
        "com.company.project.config"
    }
)
public class LegacyApplication {

    public static void main(String[] args) {
        SpringApplication.run(LegacyApplication.class, args);
    }
}

这样,Spring 只会在上述几个包中查找:

步骤 2:对非核心模块使用@Import手动引入

如果某些第三方集成、独立模块不想被大范围扫描,可以:

示例:

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({
    ThirdPartyDataSourceConfig.class,
    ExternalJobSchedulerConfig.class
})
public class ExtraConfig {
}

主启动类仍然只扫描业务核心包,而额外的集成模块通过 @Import 精准引入。

2.3 原理说明

包扫描阶段主要做两件事情:

缩小扫描范围带来的好处:

2.4 注意事项

注意:扫描包配置不当会导致 Bean 漏扫

如果某些核心业务 Bean 所在包没被包含进来,会出现启动失败、依赖找不到、Controller 不生效等问题;

调整扫描范围后,建议:

三、优化点 3:优化 JVM 启动参数(适配 JDK 8)

3.1 问题原因

Spring Boot 1.4/1.5 多数运行在 JDK 8 上,如果 JVM 参数不合理,会导致:

老项目常见问题:

3.2 推荐 JVM 参数示例(JDK 8)

开发环境(以启动速度优先)

java \
  -Xms512m \
  -Xmx512m \
  -XX:MetaspaceSize=128m \
  -XX:MaxMetaspaceSize=256m \
  -XX:+UseCompressedOops \
  -XX:+UseG1GC \
  -XX:MaxGCPauseMillis=200 \
  -XX:+PrintGCDetails \
  -XX:+PrintGCDateStamps \
  -Xloggc:logs/gc.log \
  -Xverify:none \
  -Dspring.profiles.active=dev \
  -jar legacy-app.jar

关键参数说明:

生产环境(兼顾稳定性)

java \
  -Xms2g \
  -Xmx2g \
  -XX:MetaspaceSize=256m \
  -XX:MaxMetaspaceSize=512m \
  -XX:+UseCompressedOops \
  -XX:+UseG1GC \
  -XX:MaxGCPauseMillis=200 \
  -XX:+PrintGCDetails \
  -XX:+PrintGCDateStamps \
  -Xloggc:/data/logs/gc.log \
  -Dspring.profiles.active=prod \
  -jar legacy-app.jar

生产环境建议:

3.3 原理说明

JVM 启动阶段涉及:

合理配置 JVM 参数可以:

3.4 注意事项

注意:-Xverify:none 不建议在生产环境使用

四、优化点 4:延迟初始化非核心 Bean

4.1 问题原因

默认情况下,Spring 在启动时会:

对于很多老项目来说,这些 Bean:

但它们却在启动阶段“抢占时间”,导致整体启动明显偏慢。

4.2 操作步骤 1:全局延迟初始化(慎用)

application.properties 中配置:

spring.main.lazy-initialization=true

Spring Boot 1.4/1.5 没有这个统一属性,可以通过 自定义 BeanFactoryPostProcessor 或升级到 2.x 后使用。若你已做了小版本升级(如维护分支升级到 2.1/2.3),可以直接用此配置。对于原生 1.4/1.5,可优先考虑“局部延迟初始化”。

4.3 操作步骤 2:局部延迟初始化(推荐)

非核心、非强依赖链上的 Bean 使用 @Lazy

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

@Service
@Lazy
public class ReportGenerateService {

    public void generateDailyReport() {
        // 生成报表的耗时逻辑
    }
}

也可以在依赖注入处使用:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    @Lazy
    private ReportGenerateService reportGenerateService;

    public void createOrder() {
        // 下单逻辑
        // 只有真正需要生成报表时,才会初始化 ReportGenerateService
    }
}

4.4 原理说明

将非核心 Bean 延迟初始化,可以:

4.5 注意事项

注意:全局延迟初始化可能隐藏启动期异常

某些 Bean 的配置错误,仅在其首次访问时才会抛出异常;

如果这些 Bean 是核心功能的一部分,可能在系统运行一段时间后才抛出问题;

建议:

五、优化点 5:移除冗余依赖与插件

5.1 问题原因

老项目演进多年后,典型现象是:

这些冗余依赖和插件会导致:

5.2 操作步骤 1:用dependency:tree分析依赖

在项目根目录执行:

mvn dependency:tree > dependency-tree.txt

打开 dependency-tree.txt,重点关注:

对于明确不需要的依赖,可在 pom.xml 中排除,例如:

1)排除内置 Tomcat(改用外置容器时):

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- 使用外部容器时可以去掉内嵌容器相关依赖 -->
</dependencies>

2)排除不必要的自动配置模块:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
        </exclusion>
    </exclusions>
</dependency>

5.3 操作步骤 2:精简spring-boot-maven-plugin配置

典型的插件配置:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.5.22.RELEASE</version>
            <configuration>
                <mainClass>com.company.project.LegacyApplication</mainClass>
                <!-- 如果不需要,关闭某些额外的 repackage 行为或自定义 layout -->
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

建议:

5.4 原理说明

清理冗余依赖与插件的本质,就是减少“项目的体重”。

5.5 注意事项

注意:依赖移除/排除前要确认影响范围

使用 mvn dependency:analyze 辅助分析未使用依赖,但结果仅供参考

移除或排除依赖后,请务必:

六、优化效果验证:如何量化“到底快了多少”

做完优化,如果没有数据支撑,很难说服团队。这里给出两种简单实用的验证方式。

6.1 在main方法中添加启动计时日志

在主启动类中加入简单计时代码:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LegacyApplication {

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        SpringApplication.run(LegacyApplication.class, args);
        long end = System.currentTimeMillis();
        System.out.println(">>> Application started in " + (end - start) + " ms <<<");
    }
}

每次启动时,控制台会打印:

>>> Application started in 12345 ms <<<

你可以:

6.2 使用 Spring Boot Actuator 分析 Bean 初始化耗时

如果项目中已集成 Actuator,可以启用相关端点。

1)POM 中引入依赖(如尚未添加)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2)在配置中开放必要端点(以 1.5.x 为例)

management.security.enabled=false
endpoints.metrics.enabled=true
endpoints.beans.enabled=true

然后访问:

Tip: 在 2.x 中可以借助更多细粒度的指标(如 startup 相关指标)进行可视化分析。

七、总结与拓展

7.1 5 个优化点的实战优先级

在不做大规模重构、不升级大版本的前提下,可以按下面的优先级落地执行:

配合这 5 个优化点,实践中老项目启动时间从 30 秒+ 压缩到 10~15 秒 是完全可以做到的。

7.2 拓展建议

逐步升级到 Spring Boot 2.x

引入 Spring Boot DevTools 提升开发体验

建议:老项目的性能治理,要把“启动时间优化”纳入整体技术债清单

以上就是SpringBoot启动慢的5个优化技巧分享的详细内容,更多关于SpringBoot启动优化的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文