说说 Springboot 的启动流程?
-
启动 main() 方法:应用从
main()
方法启动,并通过SpringApplication.run()
引导应用启动。 -
创建SpringApplication:应用会创建
SpringApplication
对象,推断应用类型、设置初始化器、设置启动监听器、确定主应用类。
- 准备环境:Spring Boot 在启动过程中准备应用环境,加载配置文件、系统环境变量以及命令行参数。
- 创建并刷新 ApplicationContext:创建应用上下文,加载配置类和自动配置类,注册 Bean 并执行依赖注入等初始化操作。
- 在刷新上下文时启动嵌入式 Web 服务器: 对于 Web 应用,Spring Boot 会自动启动嵌入式 Web 容器(默认 Tomcat),并注册相关的 Servlet 和 Filter。
- 发布应用已启动事件:对应监听 stated 事件逻辑会被触发。
-
执行 CommandLineRunner 和 ApplicationRunner: 在应用启动完成后,执行实现了
CommandLineRunner
和ApplicationRunner
接口的初始化逻辑。 -
发布 ready 事件、应用启动完成:触发
ApplicationReadyEvent
,应用进入运行状态,处理业务请求或任务。
什么是 Spring Boot?
Spring Boot 是一个简化 Spring 应用程序开发的框架。它的主要目标是减少 Spring 应用程序的配置和开发复杂性,使我们能够更快地构建、测试和部署 Spring 应用。
Spring Boot 主要特点
-
简化配置:Spring Boot 通过自动配置(
@EnableAutoConfiguration
),根据项目中的类路径依赖、环境变量等自动为应用配置适当的 Spring 模块,避免了大量的 XML 配置。 -
内置服务器:Spring Boot 内置了 Tomcat、Jetty、Undertow 等服务器,应用程序可以直接通过
java -jar
方式启动,而不需要部署到外部的 Web 服务器中。 - 快速开发:Spring Boot 提供了开箱即用的项目结构、默认配置和依赖管理,支持快速原型开发。它还提供了许多常用的开发工具(如开发时热部署、应用健康检查等)。
- 独立运行:Spring Boot 应用打包成一个独立的 JAR 或 WAR 包,可以通过命令行直接运行,简化了部署过程。
SpringBoot 的核心特性有哪些?
- 开箱即用,内嵌服务器。 spring boot 可以省略以前繁琐的 tomcat 配置,快速创建一个 web 容器。
- 自动化配置。 在 spring boot 中我们可以按照自动配置的规定(将自动加载的 bean 写在自己jar 包当中的 meta/info/spring.factories 文件中或者通过的注解 @Import 导入时加载指定的类)这样我们的配置类就会被 Springboot 自动加载到容器当中。 同时还支持通过改写yaml 和 propreties来覆盖默认配置
- 支持 jar 包运行。 传统部署web 容器都是打成 war 包放在 tomcat 中。spring boot 可以打成 jar 包只要有 java 运行环境即可运行 web 容器。
- 完整的生态支持。 spring boot 可以随意整合 spring 全家桶的支持。像 Actuator 健康检查模块,Spring Data JPA 数据库模块,Spring Test 测试模块。这些都可以很优雅的集成在 springboot 当中。
- 监控、健康检查支持。 spring boot Actuator 支持开发者监控应用的运行状态,包括性能指标、应用信息和日志级别控制等。
SpringBoot 是如何实现自动配置的?
Spring Boot 的自动配置是通过 @EnableAutoConfiguration
注解实现,这个注解包含@Import({AutoConfigurationImportSelector.class})
注解,导入的这个类会去扫描 classpath 下所有的 META-INF/spring.factories
中的文件,根据文件中指定的配置类加载相应的 Bean 的自动配置。
Spring Boot 支持哪些嵌入 Web 容器?
1)Tomcat(默认) :Tomcat 是一种轻量级、广泛使用的 Servlet 容器
2)Jetty:Jetty 是一个高效的 Web 服务器和 Servlet 容器,通常用于嵌入式系统或对资源占用较敏感的环境。它比 Tomcat 更轻量,并且适合长连接应用(如 WebSocket、Comet)。
3)Undertow:Undertow 是一个轻量级的高性能 Web 服务器和 Servlet 容器,适合用于处理高并发的 HTTP 请求。它支持异步 IO 和 HTTP/2,是一种灵活、性能出色的选择。
4)Netty(仅限 WebFlux):对于使用 Spring WebFlux 的响应式 Web 应用,Spring Boot 支持 Netty 作为嵌入式 Web 容器。Netty 是一个非阻塞的异步事件驱动框架,非常适合响应式编程模型和高并发应用。
Spring Boot 中 application.properties 和 application.yml 的区别是什么?
它们两者的区别就在于书写格式,对配置而言效果是一样的,就是个人偏好问题。 默认优先级为:application.properties > application.yml
- application.properties 使用键值对配置,键和值之间用等号或冒号分隔
- application.yml 使用 YAML 格式,具有层级结构,使用缩进表示嵌套关系。适合复杂配置,阅读性更佳。
# application.properties
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=root
spring.datasource.password=secret
# application.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/db
username: root
password: secret
如何在 Spring Boot 中定义和读取自定义配置?
my:
custom:
property: 1234
1)使用 @Value 注解:
@Value("${my.custom.property}")
private String myProperty;
2)使用 @ConfigurationProperties 注解:
@Component
@ConfigurationProperties(prefix = "my.custom")
public class MyCustomProperties {
private String property;
}
3)使用 Environment 接口:
@Autowired
private Environment env;
public void someMethod() {
String value = env.getProperty("my.custom.property");
}
Spring Boot 配置文件加载优先级你知道吗?
简单优先级:
- 命令行参数 > JAR包外面的配置文件 > JAR包内的配置文件
- 命令行参数 >
application-{profile}.properties
>application.properties
>application.yml
Spring Boot 打成的 jar 和普通的 jar 有什么区别 ?
- SpringBoot 打包的 JAR 包可以直接部署运行(内嵌服务器,默认 Tomcat)
- 普通的 JAR 包通常需要外部服务器或容器运行(例如:Tomcat)
SpringBoot 默认同时可以处理多少个请求?
SpringBoot 默认是 Tomcat 这个 web 容器,实际上是这取决于 tomcat 的线程池配置。
tomcat 的默认核心线程数是 10,最大线程数 200,队列长度无限。但是它的线程池机制和 JDK 默认线程池不一样,因为主要是 I/O 密集型的任务,所以 tomcat 改造了线程池策略,在核心线程数满了之后,会直接创建线程到最大线程数。
所以,在默认的配置下,同一时刻,可以处理 200 个请求。 其他的请求只能排队了。
可以通过 server.tomcat.max-threads
修改最大最大工作线程数。
如何理解 Spring Boot 中的 starter?
在 Spring Boot 中,Starter 是一组有用的依赖集合,用于简化构建配置。Spring Boot 通过 Starter POMs 提供了各种常用功能模块的集成,开发者只需引入一个 Starter 依赖,便可以自动获得该模块的所有相关依赖和配置,而无需手动添加多个依赖库和配置文件。
有点像我们去买一些必需品,然后有人打包成一个套餐售卖,我们就不需要一个一个再去找了,直接一次性打包拿走,节省了时间。
在 Spring Boot 中你是怎么使用拦截器的?
拦截器可以用来进行权限校验、日志记录、处理异常等问题
1)创建拦截器类: 实现 HandlerInterceptor 接口,并实现接口中的方法,方法里面包括了几个请求时间点:请求前、请求后 、整个请求结束后(用于资源清理等操作)。
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("请求开始前");
return true; // 返回 true 继续处理,false 则拦截请求
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("请求后");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception {
System.out.println("请求完成");
}
}
2)注册拦截器: 通过实现 WebMvcConfigurer 的 addInterceptors 方法来添加自定义的拦截器。
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/api/**"); // 拦截指定路径
}
}
说说你对 Spring Boot 事件机制的了解?
Spring Boot 的事件机制,实际上是基于 Spring 的事件机制实现的,通过发布-订阅模式(使用观察者设计模式) ,主要用于应用程序中各个组件之间进行消息传递和解耦。
作用总结
- 解耦:通过事件机制,可以在不同组件之间传递消息,而不需要它们之间有直接的依赖关系,从而提高了代码的可维护性和扩展性。
- 异步处理:某些事件可以异步处理,从而提高应用程序的响应速度和性能。
- 状态通知:通过事件机制,可以通知应用程序的不同部分发生了某些特定的状态变化,比如启动完成、环境准备就绪等。
步骤
-
创建事件类:定义一个事件类,继承自
ApplicationEvent
,或者任何自定义对象(从 Spring 4.2 开始,事件不再局限于ApplicationEvent
,可以是任意对象) -
发布事件:在需要的地方发布事件,使用
ApplicationEventPublisher
-
创建事件监听器:使用
@EventListener
注解创建事件监听器。 - 使用事件发布者:在应用程序中调用事件发布者的方法来发布事件
自定义事件例子
1)创建事件类
public class MyCustomEvent extends ApplicationEvent {
private final String message;
public MyCustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage(){
return message;
}
}
2)发布事件
@Service
public class MyEventPublisher {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void publishEvent(String message) {
MyCustomEvent event = new MyCustomEvent(this, message);
eventPublisher.publishEvent(event);
}
}
3)监听事件
@Component
public class MyCustomListener {
@EventListener
public void handleCustomEvent(MyCustomEvent event) {
System.out.println("监听到消息 - " + event.getMessage());
}
}
4)测试
@SpringBootTest
class TestSpringBootApplicationTests {
@Autowired
private MyEventPublisher myEventPublisher;
@Test
void contextLoads() {
myEventPublisher.publishEvent("哈喽!");
myEventPublisher.publishEvent("你好!");
}
}
监听到消息 - 哈喽!
监听到消息 - 你好!
Spring Boot 中如何实现异步处理?
主要有四种方式来实现异步处理:
- 使用 @Async 注解
- 使用 CompletableFuture(Java 8 引入的一个强大的异步编程工具)
- 使用 @Scheduled 注解
- 使用线程池