前端视角 Java Web 入门手册 5.2:真实世界 Web 开发——Spring Boot 应用启动流程

1. 概述

Spring Boot 通过简化 Spring 应用的配置和部署,极大地加快了开发速度。启动一个 Spring Boot Web应用涉及多个步骤,从引导应用到监听和处理 HTTP 请求。依赖注入作为 Spring 框架的核心特性,在应用启动和运行中起到了至关重要的作用

2. 启动流程的关键步骤

2.1 main() 方法与 SpringApplication.run()

入口点 :Spring Boot应用的启动从包含 main() 方法的主类开始。该方法调用 SpringApplication.run(),这是启动整个Spring Boot应用的关键步骤

java 复制代码
@SpringBootApplication
public class MySpringBootApp {

    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApp.class, args);
    }
}
  • @SpringBootApplication:这是一个复合注解,包含了 @Configuration、@EnableAutoConfiguration 和 @ComponentScan
  • SpringApplication.run():启动Spring Boot应用,创建并刷新应用上下文

2.2 创建应用上下文(ApplicationContext)

SpringApplication.run() 方法的核心职责之一是创建 应用上下文(ApplicationContext) ,这是Spring应用的核心容器,负责管理和配置应用中的所有Beans。

步骤

  1. 初始化Spring应用:确定应用类型
  2. 创建 ApplicationContext:具体实现通常是 AnnotationConfigServletWebServerApplicationContext,适用于基于注解的配置和Servlet Web服务器
  3. 加载配置类 :解析 @SpringBootApplication 和其他配置注解,加载 Bean 定义

2.3 自动配置(Auto-Configuration)

Spring Boot 的自动配置功能通过推断项目所需要的配置,自动配置Spring应用,减少大量繁琐的手动设置

工作原理

  • 条件注解 :如 @ConditionalOnClass@ConditionalOnMissingBean,根据特定条件决定是否应用某个配置
  • 配置类加载spring.factories 文件中列出的自动配置类被加载并应用
java 复制代码
@Configuration
@ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")
public class WebMvcAutoConfiguration {
    // 自动配置Web MVC相关的Bean
}

优点

  • 简化配置:自动配置常用组件,如数据源、MVC、模板引擎等
  • 可扩展性:开发者可以通过覆盖默认配置或定义新的配置类来自定义应用

2.4 组件扫描与Bean的创建

Spring Boot 通过 组件扫描(Component Scanning) 自动发现和注册 Beans。所有被注解标记的类(如 @Component@Service@Repository@Controller 等)都会被Spring容器管理

步骤

  1. 启动组件扫描:位于主类所在的包及其子包
  2. 识别候选组件:扫描带有特定注解的类
  3. 创建Bean实例:根据依赖注入的规则创建和初始化 Bean
java 复制代码
@Service
public class GreetingService {

    public String greet() {
        return "Hello, Spring Boot!";
    }
}

@RestController
public class GreetingController {

    private final GreetingService greetingService;

    @Autowired // 自动注入GreetingService
    public GreetingController(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    @GetMapping("/greet")
    public String greet() {
        return greetingService.greet();
    }
}

2.5 依赖注入(Dependency Injection, DI)详解

依赖注入是 Spring 框架的核心特性之一,它通过外部化对象的依赖关系,降低了代码的耦合度,提高了模块的可测试性和可维护性。在 Spring Boot 应用的启动过程中,依赖注入起到了至关重要的作用

2.5.1 依赖注入的原理

依赖注入遵循 控制反转(Inversion of Control, IoC) 的原则,即对象不再自行创建或查找其依赖,而是由外部容器(如 Spring 的 ApplicationContext)负责注入所需的依赖

核心概念

  • IoC容器:Spring 的 ApplicationContext 即为 IoC 容器,负责管理Bean的生命周期和依赖关系
  • Bean:由 Spring 容器管理的对象
  • 依赖:Bean 所需要的其它 Bean 或资源

2.5.2 依赖注入的方式

Spring 支持多种依赖注入方式,主要包括:

  1. 构造器注入(Constructor Injection) :通过构造函数注入依赖,推荐使用
  2. Setter注入(Setter Injection) :通过 Setter 方法注入依赖
  3. 字段注入(Field Injection) :直接在字段上使用 @Autowired 注解注入依赖,不推荐使用,因为不利于测试和可维护性
  • 构造器注入
java 复制代码
@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // 业务逻辑方法
}
  • Setter注入
java 复制代码
@Service
public class UserService {
    private UserRepository userRepository;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // 业务逻辑方法
}
  • 字段注入(不推荐):
java 复制代码
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    // 业务逻辑方法
}

2.5.3 Bean 的生命周期与依赖注入

在 Spring Boot 应用启动过程中,Beans 的创建和依赖注入遵循一定的生命周期:

  1. 实例化(Instantiation) :Spring 容器根据 Bean 定义创建 Bean 的实例
  2. 填充属性(Populate Properties) :注入 Bean 的依赖
  3. 调用初始化方法(Initialization) :执行Bean的初始化逻辑,如实现 InitializingBean 接口的 afterPropertiesSet() 方法,或使用 @PostConstruct 注解的方法
  4. 就绪使用(Ready to Use) :Bean 已准备好被应用程序使用
  5. 销毁(Destruction) :应用关闭时,执行Bean的销毁逻辑,如实现 DisposableBean 接口的 destroy() 方法,或使用 @PreDestroy 注解的方法
java 复制代码
@Service
public class ExampleService implements InitializingBean, DisposableBean {
    
    @Autowired
    private AnotherService anotherService;
    
    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化逻辑
    }
    
    @Override
    public void destroy() throws Exception {
        // 销毁逻辑
    }
}

使用 @PostConstruct @PreDestroy 注解

java 复制代码
@Service
public class ExampleService {
    
    @Autowired
    private AnotherService anotherService;
    
    @PostConstruct
    public void init() {
        // 初始化逻辑
    }
    
    @PreDestroy
    public void cleanup() {
        // 销毁逻辑
    }
}

2.5.4 依赖注入在启动流程中的作用

在 Spring Boot Web 应用的启动过程中,依赖注入涉及以下几个关键步骤:

  1. 组件扫描 :Spring扫描指定包下的所有类,识别带有注解(如 @Component@Service@Repository@Controller 等)的 Bean
  2. 创建Bean实例:根据扫描到的Bean定义,Spring创建Bean的实例。
  3. 解析依赖关系:Spring 识别 Bean 之间的依赖关系,并根据依赖注入方式(构造器、Setter、字段)注入所需的依赖
  4. 初始化Bean:执行 Bean 的初始化方法,完成 Bean 的准备工作
  5. 注册Bean到容器:将 Bean 注册到 ApplicationContext 中,供其它组件使用

假设有以下组件:

  • UserRepository :数据访问层接口,继承自 JpaRepository
  • UserService :服务层,依赖 UserRepository
  • UserController :控制器,依赖 UserService
java 复制代码
// UserRepository.java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // 自定义查询方法
}

// UserService.java
@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    // 其他业务逻辑方法
}

// UserController.java
@RestController
@RequestMapping("/users")
public class UserController {
    
    private final UserService userService;
    
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }
    
    // 其他API端点
}

启动流程中的依赖注入

  1. 组件扫描:Spring 扫描 com.example.hellospring 及其子包,发现三个 Bean:UserRepository、UserService、UserController
  2. 创建 UserRepository 实例:Spring 根据接口创建动态代理实例,并注入到容器中
  3. 创建 UserService 实例:Spring 识别 UserService 构造器中的 UserRepository 依赖,并注入 UserRepository 实例
  4. 创建 UserController 实例:Spring识别 UserController 构造器中的 UserService 依赖,并注入 UserService 实例
  5. 初始化和注册
    • 所有 Bean 的初始化方法被调用,完成 Bean 的配置和准备
    • Bean 被注册到 ApplicationContext 中,供应用程序使用

这样通过依赖注入,Spring Boot 确保各个组件之间的耦合度低,且责任清晰,便于测试和维护

2.6 设置嵌入式服务器(Embedded Server)

对于 Web 应用,Spring Boot 通常使用嵌入式服务器(如Tomcat、Jetty 或 Undertow)来运行应用,避免了传统的部署方式

  1. 解析依赖 :如 spring-boot-starter-web 会引入 Tomcat 依赖
  2. 配置服务器:根据配置文件和自动配置设置服务器参数
  3. 创建服务器实例:创建一个 Tomcat 服务器,并配置端口(默认8080)

2.7 启动嵌入式服务器并监听请求

一旦嵌入式服务器被配置和创建,它会被启动并开始监听指定端口的 HTTP 请求

  1. 初始化服务器:启动 Tomcat 容器
  2. 部署应用:将 Spring 应用部署到服务器中,注册 Servlet、过滤器等
  3. 开始监听:服务器开始接受并处理来自客户端的 HTTP 请求

2.8 请求处理流程

当服务器接收到 HTTP 请求时,以下步骤会被执行:

  1. DispatcherServlet 接收请求:作为前端控制器,负责分发请求到具体的处理器
  2. 获取 Handler:DispatcherServlet 通过 HandlerMapping 找到对应的 Controller 方法
  3. 调用 Controller 方法:执行业务逻辑,通常涉及服务层和数据访问层
  4. 返回响应:将结果打包成 HTTP 响应,并通过 DispatcherServlet 发送回客户端

处理流程

  1. 请求被 DispatcherServlet 接收
  2. HandlerMapping 找到 GreetingController.greet() 方法
  3. 调用 greet() 方法,返回 "Hello, Spring Boot!"
  4. DispatcherServlet 将响应返回给客户端

3. 启动过程中的关键类与组件

理解 Spring Boot 启动过程的关键类和组件有助于深入了解其工作机制。以下是一些重要的类和组件:

  • SpringApplication:核心类,用于启动 Spring Boot 应用。配置应用上下文,触发自动配置等
  • ApplicationContext:Spring 的 IoC 容器,管理和配置应用中的所有 Beans
  • AutoConfiguration:自动配置类,基于项目依赖和配置自动配置 Spring 组件
  • DispatcherServlet:Spring MVC 的核心 Servlet,负责处理和分发 HTTP 请求
  • EmbeddedServletContainerFactory:用于创建嵌入式服务器实例的工厂类
  • BeanFactoryBeanDefinition:底层接口和类,定义和管理Bean的创建与注入
  • Environment:封装了应用的环境信息,如配置属性、系统属性等
  • Banner:Spring Boot 启动时显示的横幅,可以自定义或关闭

4. 启动流程图

Spring Boot Web 应用的启动流程图大致如下,可以更直观地理解整个过程:

plain 复制代码
+--------------------+
|     main() 方法     |
|  (调用 SpringApplication.run()) |
+---------+----------+
|
v
+---------+----------+
| SpringApplication  |
|     初始化         |
+---------+----------+
|
v
+---------+----------+
| 创建 ApplicationContext |
|    (IoC 容器)         |
+---------+----------+
|
v
+---------+----------+
|    自动配置 Auto-Configuration     |
|   (根据依赖和配置)                |
+---------+----------+
|
v
+---------+----------+
| 组件扫描与Bean创建   |
| @Component, @Service, etc. |
+---------+----------+
|
v
+---------+----------+
|   依赖注入(DI)    |
|    注入Bean依赖      |
+---------+----------+
|
v
+---------+----------+
|   设置嵌入式服务器  |
|   (Tomcat, Jetty, etc.)|
+---------+----------+
|
v
+---------+----------+
| 启动嵌入式服务器并监听请求 |
+---------+----------+
|
v
+---------+----------+
| 处理HTTP请求       |
| DispatcherServlet -> Controllers |
+--------------------+

5. 总结

通过深入了解 Spring Boot Web 应用的启动流程,特别是依赖注入的部分,可以更好地理解其工作原理,从而更有效地开发和调试应用:

  • 入口点 :应用启动从 main() 方法开始,调用 SpringApplication.run()
  • 应用上下文 :通过 ApplicationContext 管理和配置所有 Beans,实现依赖注入和 IoC
  • 自动配置:根据项目依赖和配置自动配置 Spring 组件,简化开发过程
  • 组件扫描:自动发现和注册带有特定注解的 Bean,支持依赖注入
  • 依赖注入:通过构造器、Setter 或字段注入方式,管理 Bean 之间的依赖关系
  • 嵌入式服务器:内置服务器(Tomcat)使应用可独立运行,简化部署
  • 请求处理:DispatcherServlet 作为前端控制器,负责分发和处理 HTTP 请求
相关推荐
whoarethenext18 分钟前
qt的基本使用
开发语言·c++·后端·qt
m0_684598531 小时前
如何开发英语在线训练小程序:从0到1的详细步骤
java·微信小程序·小程序·小程序开发
ml130185288741 小时前
开发一个环保回收小程序需要哪些功能?环保回收小程序
java·大数据·微信小程序·小程序·开源软件
zybishe2 小时前
免费送源码:Java+ssm+MySQL 酒店预订管理系统的设计与实现 计算机毕业设计原创定制
java·大数据·python·mysql·微信小程序·php·课程设计
anlogic4 小时前
Java基础 4.12
java·开发语言
weisian1514 小时前
Java常用工具算法-7--秘钥托管云服务2(阿里云 KMS)
java·安全·阿里云
草捏子4 小时前
主从延迟导致数据读不到?手把手教你架构级解决方案
后端
橘猫云计算机设计4 小时前
基于Python电影数据的实时分析可视化系统(源码+lw+部署文档+讲解),源码可白嫖!
数据库·后端·python·信息可视化·小程序·毕业设计
Alt.94 小时前
SpringMVC基础二(RestFul、接收数据、视图跳转)
java·开发语言·前端·mvc
寒页_4 小时前
2025年第十六届蓝桥杯省赛真题解析 Java B组(简单经验分享)
java·数据结构·经验分享·算法·蓝桥杯