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 和 @ComponentScanSpringApplication.run()
:启动Spring Boot应用,创建并刷新应用上下文
2.2 创建应用上下文(ApplicationContext)
SpringApplication.run()
方法的核心职责之一是创建 应用上下文(ApplicationContext) ,这是Spring应用的核心容器,负责管理和配置应用中的所有Beans。
步骤:
- 初始化Spring应用:确定应用类型
- 创建
ApplicationContext
:具体实现通常是AnnotationConfigServletWebServerApplicationContext
,适用于基于注解的配置和Servlet Web服务器 - 加载配置类 :解析
@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容器管理
步骤:
- 启动组件扫描:位于主类所在的包及其子包
- 识别候选组件:扫描带有特定注解的类
- 创建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 支持多种依赖注入方式,主要包括:
- 构造器注入(Constructor Injection) :通过构造函数注入依赖,推荐使用
- Setter注入(Setter Injection) :通过 Setter 方法注入依赖
- 字段注入(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 的创建和依赖注入遵循一定的生命周期:
- 实例化(Instantiation) :Spring 容器根据 Bean 定义创建 Bean 的实例
- 填充属性(Populate Properties) :注入 Bean 的依赖
- 调用初始化方法(Initialization) :执行Bean的初始化逻辑,如实现
InitializingBean
接口的afterPropertiesSet()
方法,或使用@PostConstruct
注解的方法 - 就绪使用(Ready to Use) :Bean 已准备好被应用程序使用
- 销毁(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 应用的启动过程中,依赖注入涉及以下几个关键步骤:
- 组件扫描 :Spring扫描指定包下的所有类,识别带有注解(如
@Component
、@Service
、@Repository
、@Controller
等)的 Bean - 创建Bean实例:根据扫描到的Bean定义,Spring创建Bean的实例。
- 解析依赖关系:Spring 识别 Bean 之间的依赖关系,并根据依赖注入方式(构造器、Setter、字段)注入所需的依赖
- 初始化Bean:执行 Bean 的初始化方法,完成 Bean 的准备工作
- 注册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端点
}
启动流程中的依赖注入:
- 组件扫描:Spring 扫描 com.example.hellospring 及其子包,发现三个 Bean:UserRepository、UserService、UserController
- 创建 UserRepository 实例:Spring 根据接口创建动态代理实例,并注入到容器中
- 创建 UserService 实例:Spring 识别 UserService 构造器中的 UserRepository 依赖,并注入 UserRepository 实例
- 创建 UserController 实例:Spring识别 UserController 构造器中的 UserService 依赖,并注入 UserService 实例
- 初始化和注册 :
- 所有 Bean 的初始化方法被调用,完成 Bean 的配置和准备
- Bean 被注册到
ApplicationContext
中,供应用程序使用
这样通过依赖注入,Spring Boot 确保各个组件之间的耦合度低,且责任清晰,便于测试和维护
2.6 设置嵌入式服务器(Embedded Server)
对于 Web 应用,Spring Boot 通常使用嵌入式服务器(如Tomcat、Jetty 或 Undertow)来运行应用,避免了传统的部署方式
- 解析依赖 :如
spring-boot-starter-web
会引入 Tomcat 依赖 - 配置服务器:根据配置文件和自动配置设置服务器参数
- 创建服务器实例:创建一个 Tomcat 服务器,并配置端口(默认8080)
2.7 启动嵌入式服务器并监听请求
一旦嵌入式服务器被配置和创建,它会被启动并开始监听指定端口的 HTTP 请求
- 初始化服务器:启动 Tomcat 容器
- 部署应用:将 Spring 应用部署到服务器中,注册 Servlet、过滤器等
- 开始监听:服务器开始接受并处理来自客户端的 HTTP 请求
2.8 请求处理流程
当服务器接收到 HTTP 请求时,以下步骤会被执行:
- DispatcherServlet 接收请求:作为前端控制器,负责分发请求到具体的处理器
- 获取 Handler:DispatcherServlet 通过 HandlerMapping 找到对应的 Controller 方法
- 调用 Controller 方法:执行业务逻辑,通常涉及服务层和数据访问层
- 返回响应:将结果打包成 HTTP 响应,并通过 DispatcherServlet 发送回客户端
处理流程:
- 请求被 DispatcherServlet 接收
- HandlerMapping 找到
GreetingController.greet()
方法 - 调用
greet()
方法,返回 "Hello, Spring Boot!" - DispatcherServlet 将响应返回给客户端
3. 启动过程中的关键类与组件
理解 Spring Boot 启动过程的关键类和组件有助于深入了解其工作机制。以下是一些重要的类和组件:
SpringApplication
:核心类,用于启动 Spring Boot 应用。配置应用上下文,触发自动配置等ApplicationContext
:Spring 的 IoC 容器,管理和配置应用中的所有 BeansAutoConfiguration
:自动配置类,基于项目依赖和配置自动配置 Spring 组件DispatcherServlet
:Spring MVC 的核心 Servlet,负责处理和分发 HTTP 请求EmbeddedServletContainerFactory
:用于创建嵌入式服务器实例的工厂类BeanFactory
和BeanDefinition
:底层接口和类,定义和管理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 请求