SpringBoot面试题
Spring、Spring MVC、SpringBoot是什么关系
Spring包含多个功能模块
Spring MVC是其中的一个模块,专门处理Web请求
SpringBoot只是简化了配置,如果需要构建MVC架构的Web程序,还是需要使用Spring MVC作为 MVC框架,只是说SpringBoot简化了Spring MVC的很多配置,真正做到开箱即用
Spring IOC
IOC (Inversion of Control :控制反转) 将原本在程序中手动创建对象的控制权,交由Spring框架来管理
控制:指的是对象的创建(实例化、管理)的权力
反转:控制权交给外部环境(Spring框架、IOC容器)
@Component 和 @Bean
@Component 注解作用于类;@Bean 注解作用于方法
当我们引用第三方库中的类需要装配到Spring容器时,只能通过@Bean来实现
@Autowired和@Resource
@Autowired 属于Spring内置的注解,默认的注入方式为bytype(根据类型进行匹配),就是说会优先根据接口类型去匹配并注入Bean(接口的实现类)。当一个接口存在多个接口实现类的话,byType这种方式就无法正确注入对象了。因为这个时候Spring会同时找到多个满足条件的选择,默认情况下,它自己不知道选择哪一个。这种情况下,注入方式会变为byName(根据名称进行匹配),这个名称通常及时类名(首字母小写)
通过 @Qualifier 注解可以显式指定名称而不是依赖变量的名称
@Resource数据JDK提供的注解,默认注入方式为byName。如果无法通过byName匹配到对应的Bean,注入方式会变为byType
@Resource两个常用的属性:name(名称)、type(类型)。若仅指定name属性则注入方式为byName,若仅指定type属性则注入方式为byType,如果同时指定name和type,则注入方式为byType+byName。
注入Bean的方法
构造函数注入:通过类的构造函数来注入依赖项
Setter注入:通过类的Setter方法来注入依赖性
Field(字段)注入:直接在类的字段上使用注解(@Autowired或@Resource)来注入依赖项
Spring官方推荐构造函数注入
依赖完整性:确保所有依赖在对象创建时就被注入,避免空指针异常风险
不可变性:有助于创建不可变对象,提高线程安全性
初始化保证:组件在使用前已完全初始化,减少潜在的错误
测试便利性:在单元测试中,可以直接通过构造函数传入模拟的依赖项,不必依赖Spring容器进行注入
Bean的作用域
singleton:IOC容器中只有唯一的bean实例。Spring中的bean默认都是单例的,是对单例设计模式的应用
prototype:每次获取都会创建一个新的bean实例。连续getBean()两次,得到的是不同的Bean实例
request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效
session:每一个HTTP Session会产生一个新的bean,该bean仅在当前HTTP session有效
Bean是线程安全的吗
Spring框架中的Bean是否安全,取决于其作用域和状态
prototype作用域下,不存在资源竞争问题,不存在线程安全问题
singleton作用域下,IOC容器只有唯一的bean实例,可能会存在资源竞争问题。若bean有状态,就存在线程安全问题(有状态:是指具有实例变量的对象,可以保存数据)
Bean的生命周期

Bean的生命周期从Spring容器启动开始,首先根据配置或注解扫描获取Bean的定义信息,随后通过实例化对象并填充属性,完成依赖注入
如果Bean实现了诸如BeanNameAware等Aware接口,容器会在此阶段回调相关方法使其感知自身信息,接下来,BeanPostProcessor的postProcessBeforeInitialization方法被调用,执行初始化前的自定义逻辑,如 处理@PostConstruct注解的方法
随后,容器触发初始化回调,包括InitializingBean接口的afterPropertiesSet方法或通过XML、注解定义的初始化方法。
BeanPostProcessor的postProcessAfterInitilization在此之后执行。常见于生成AOP代理对象等增强处理。
此时Bean已就绪,可被应用程序使用。
当容器关闭时,销毁流程启动,依次执行@PreDestory注解的方法、DisposableBean接口的destory方法或配置的销毁方法,最终完成Bean的资源释放与生命周期的终结
解决Sping中的循环依赖问题
| 缓存名称 | 描述 |
|---|---|
| singletonObjects | 一级缓存:存放完全初始化好的Bean(成品对象) |
| earlySingletonObjects | 二级缓存:存放早期暴露的Bean(已实例化但未填充属性,未初始化) |
| singletonFactories | 三级缓存:存放Bean的工厂对象(ObjectFactory),用于生成早期引用 |
以A依赖B,B依赖A为例
- 创建Bean A
- 实例化A
- 将A的工厂对象放入三级缓存
- 填充A的属性
- 创建Bean B
- 实例化B
- 将B的工厂对象放入三级缓存
- 填充B的属性
- 解决B对A的依赖
- 从三级缓存中获取A的工厂对象,生成A的早期引用
- 将A的早期引用存入二级缓存,并从三级缓存中删除A的工厂
- 将A的早期引用注入B中,完成B的属性填充和初始化
- 将初始化后的B存入一级缓存
- 完成A的创建
- 从一级缓存中获取已初始化的B,注入到A中
- 完成A的属性填充和初始化
- 将A存入一级缓存,并从二级缓存中删除A的引用
注意点:
仅支持单例Bean的循环依赖
原型(Prototype)作用域的Bean无法通过缓存解决循环依赖,Spring会直接抛出异常
构造器注入无法解决循环依赖
若循环依赖通过构造函数参数注入(而非Setter方法或字段注入),Spring无法提前暴露对象,会抛出BeanCurrenbtlyInCteationException
@Lazy是否能解决循环依赖
在一定程度上可以。
- Spring创建A时,发现它依赖B,但B被标记位@Lazy
- 不立即初始化B,而是注入一个B的代理对象(Spring动态生成)
- 当A的方法首次调用b.xx()时,代理对象才会触发B的实际初始化
- 此时B初始化时再去注入A,由于A已经存在,循环依赖被解开
Spring动态代理默认是哪种
Spring Boot 2.x以上默认启用 proxyTargetClass=true,因此无论目标类是否实现接口,统一使用CGLIB生成代理
Spring中拦截器和过滤器的区别
过滤器(Filter)是Servlet规范的一部分,其作用范围覆盖整个Web应用,能处理所有进入Servlet容器的请求。如 修改请求参数、设置字符编码或实现全局安全控制。它的执行时机在请求到达DispatcherServlet之前,因此可用作静态资源等非Spring管理的请求
拦截器(Interceptor)是Spring MVC框架提供的组件,其实现依赖于HandlerInterceptor接口,通过Spring的配置类注册到拦截器中。它的核心作用范围集中在Spring管理的控制器(Controller)层,能够在请求进入具体Controller方法前(preHandle)、方法执行后视图渲染前(postHandle)以及整个请求完成后(afterCompletion)这3个关键点插入逻辑。
所以拦截器更适合处理与业务紧密相关的操作。如 基于会话的权限校验、日志记录或接口的性能监控。
执行顺序:
整体过滤器会优先于拦截器完成。过滤器更偏向底层请求的通用处理;拦截器则聚焦于Spring MVC流程的业务逻辑增强
Spring Boot的配置优先级
从高到低
- 命令行参数
- java系统属性
- application.properties
- application.yml
Spring Boot自动配置
- SpringBootApplication注解,包含3个注解
| @SpringBootConfiguration | 标记为一个Spring配置类,类似于@Configuration |
| @EnableAutoConfiguration | 启用SpringBoot的自动配置机制 |
| @ComponentScan | 扫描当前包及其子包下所有Spring组件 |
| @EnableAutoConfiguration | 告诉Spring Boot启动时自动配置Spring应用上下文,引入 AutoConfigurationImportSelector |
| AutoConfigurationImportSelector | 自动配置类的核心处理器 |
AutoConfigurationImportSelector 类会从配置文件中(通常是spring.factories)读取所有的自动配置类,并将它们导入到应用上下文中
- spring.factories
自动配置类通过spring-boot-autoconfigure模块的META_INF/spring.factory文件来配置的,这个文件中列出了所有可以被自动加载的配置类
- 条件装配 @Conditional
Spring Boot 并不是盲目地加载所有的自动配置类,每个自动配置类通常都会使用@Conditional系列注解来进行有条件的加载。常见注解
| @ConditionalOnClass | 当类路径中存在某个类是才生效 |
| @ConditionalMissingBean | 当Spring上下文中不存在某个Bean时才生效 |
| @ConditionalOnProperty | 当某个配置类属性满足特定条件时生效 |
| @ConditionOnBean | 当Spring上下文中存在某个Bean时生效 |
@PathVariable和@RequestParam
@PathVariable用于获取路径参数 /users/{id} --->/users/123
@RequestParam 用于获取查询参数 /users?id=123
Spring MVC 的工作流程

Spring Boot支持哪些嵌入式Web容器
Tomcat、Jetty和Undertow。
项目中引入spring-boot-starter-web时,默认启用 Tomcat作为内嵌Servlet容器
- 在构建文件(Maven的pom.xml)中,从spring-boot-starter-web中排除默认的Tomcat依赖(spring-boot-starter-tomcat)
- 添加需要使用的容器依赖(spring-boot-starter-jetty或者spring-boot-starter-undertow)
@SpringBootApplication注解
@SpringbootApplication是SpringBoot的核心注解。通常用于标记应用程序的主类(即 含main方法的类)。主要作用是一站式地启用SpringBoot的关键特性,简化项目的初始化配置
@SpringBootConfiguration
继承自@Configuration,标记当前类为配置类,允许通过@Bean注解定义和注册Bean。
@EnableAutuConfiguration
启动SpringBoot的自动配置机制。根据项目依赖中META_INF/下后缀为.imports文件加载预定义的配置类,结合条件注解(@ConditionOnClass)自动配置Spring应用所需的Bean
@ComponentScan
默认扫描当前类所在的包及其包下的组件,并将它们注册为Spring Bean
Spring Boot常用的配置文件
- application.properties
采用标准的JavaProperties文件格式,即键值对(key=value)形式,每一行定义一个配置
- application.yml
采用YAML格式,这是一种层级化、以缩进表示结构的数据序列化语言。比.properties更易于阅读。尤其是在配置项较多或具有嵌套结构时,结构更清晰。通过层级嵌套避免重复书写的前缀,是配置简洁
Spring Boot 实现全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理自定义异常
@ExceptionHandler(BusinessException.class)
public ResponseEntity handleBusinessException(BusinessException ex) {
ErrorResponse error = new ErrorResponse(ex.getCode(), ex.getMessage());
return ResponseEntity.status(ex.getHttpStatus()).body(error);
}
// 处理所有未捕获的异常
@ExceptionHandler(Exception.class)
public ResponseEntity handleGenericException(Exception ex) {
ErrorResponse error = new ErrorResponse("ERROR_500", "系统内部错误");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
} Spring中实现定时任务、多节点重复执行如何避免
在Spring Boot主类或配置类添加 @EnableScheduling
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
} 使用@Scheduled注解标记方法,支持cron、fixedRate、fixedDelay
@Component
public class MyScheduledTasks {
// 每 5 秒执行一次
@Scheduled(fixedRate = 5000)
public void doTask() {
System.out.println("执行定时任务: " + new Date());
}
}
解决方法:
- 分布式锁
- 分布式任务调度工具,如 XXL_JOB
项目统一返回结果
code:状态码,遵循HTTP状态码规范并拓展因为状态码
message:对状态的描述信息
data:实际返回的业务数据
timestamp:响应时间戳
- 手动显示封装
@GetMapping("/{id}")
public Result getUser(@PathVariable Long id) {
User user = userService.getUserById(id);
return Result.success(user);
} - 自动封装
@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice Spring Boot Starters
是一组便捷的依赖描述符,它们预先打包了常用的库和配置。当我们开发Spring应用时,只添加一个Starter依赖项,即可自动引入所有必要的库和配置,而无需手动逐一添加和配置相关依赖
显著简化了开发过程,特别在处理复杂项目时尤为高效。避免繁琐和潜在错误,节省时间,提升开发效率
Spring Boot优点
- 显著提升开发效率
- 与Spring生态系统的无缝集成
- 强大的自动配置能力
- 内嵌web服务器支持
- 适合微服务框架
- 提供强大的构建工具支持
Spring Boot 怎么通过main启动web项目
Spring Boot中读取配置信息
- 使用 @value注解
// 直接注入配置项,支持默认值(如未配置则使用默认值)
@Value("${book.author:defaultAuthor}")
private String author;
- 使用@ConfigurationProperties注解
# 配置文件 application.yml
book:
name: 三国演义
author: 罗贯中
price: 30
chapters:
- 第一章
- 第二章
@Component
@ConfigurationProperties(prefix = "book")
public class BookProperties {
private String name;
private String author;
private int price;
private List chapters;
}
- 使用Environment 接口
@Autowired
private Environment env;
public String getAppInfo() {
String appName = env.getProperty("app.name");
String maxRetry = env.getProperty("app.max-retry", "defaultRetry");
}
Spring 事务传播行为
工7种,常用 前2种
PROPAGATION_REQUIRED(默认):
如果存在当前事务,则加入该事务;否则新建一个事务
所有嵌套方法共享一个事务,任一方法抛出异常会导致整个事务回滚
PROPAGATION_REQUIRES_NEW
无论当前是否存在事务,都新建一个事务
内层事务与外层事务完全隔离,外层事务回滚不影响内层事务
Spring 中BeanFactory 和FactoryBean
BeanFactory是Spring框架的核心接口,作为IOC容器的基础,负责Bean的生命周期,包括创建、配置和装配对象
FactoryBean 是一个特殊的Bean,可以在运行时根据特定条件或需求,通过getObject()方法动态控制Bean的实例化过程,在容器中通过名称加 &符 区分获取FactoryBean本身与其生成的对象
ApplicationContext
是Spring框架的核心容器接口,作为高级容器不仅继承BeanFactory的基础功能来管理和配置Bean,还拓展了众多企业级特性。
整合了资源加载、国际化支持、事件发布与监听机制,同时支持AOP、事务管理等高级功能
Spring Boot 请求参数校验
- 在DTO类上使用校验注解
public class UserDTO {
@Size(min = 2, max = 20, message = "用户名长度必须在2-20之间")
private String username;
} 在controller中使用@Vilid 注解触发校验 (或@Validated)
@PostMapping("/users")
public ResponseEntity> createUser(@RequestBody @Valid UserDTO userDTO) {
// 业务逻辑
return ResponseEntity.ok("用户创建成功");
} - 验证请求参数
直接在方法参数上使用校验注解
@GetMapping("/users/{id}")
public ResponseEntity> getUserById(@PathVariable @Min(1) Long id) {
// 业务逻辑
return ResponseEntity.ok(...);
} 需要在 Controller 类上添加 @Validated 注解 ,只能在类上添加这各注解
@RestController
@Validated
public class UserController {
// ...
} 补充: 分组校验
public class UserDTO {
@NotBlank(message = "用户名不能为空", groups = {CreateGroup.class, UpdateGroup.class})
private String username;
@Email(message = "邮箱格式不正确", groups = CreateGroup.class) // 仅创建时需要校验邮箱
private String email;
@NotNull(message = "ID不能为空", groups = UpdateGroup.class) // 仅更新时需要校验ID
private Long id;
// Getter 和 Setter
} @PostMapping("/users")
public ResponseEntity> createUser(@RequestBody @Validated(CreateGroup.class) UserDTO userDTO) {
return ResponseEntity.ok("创建用户校验通过");
} Spring Boot 处理跨域请求
Spring Boot实现异步处理
- 使用 @Async注解
- 使用ConpletableFuture
- 使用@Scheduled注解
- 使用线程池
Spring 中事件机制的理解
Spring的事件机制是一种基于观察者模式设计的解耦通信方式,允许组件在特点动作发生时通过事件传递信息,而不必直接依赖彼此。
开发者可以自定义基层ApplicationEvent的事件类,由事件发布者通过ApplicationEventPublisher触发事件,而监听者通过实现ApplicationListener接口或使用@EvevtListener注解来捕获并处理事件。
这种机制默认以同步方式运行,但结合@Async或自定义线程池可支持异步处理,提升系统响应能力。如:用户注册成功后发布事件,由监听器异步发送邮件或初始化数据,避免流程阻塞。
Spring 配置多数据源
Spring中有哪些设计模式
| 设计模式 | 作用 | 例如 |
|---|---|---|
| 工厂模式 | 隐藏对象创建的细节,由容器统一管理Bean的生命周期 | |
| 单例模式 | 节省资源,保证全局一致性 | Spring默认的Bean作用域是单例,确保每个容器中一个Bean仅有一个实例 |
| 原型模式 | Bean的作用域为prototype时,每次请求都会创建新实例 | |
| 代理模式 | Spring AOP 面向切面编程,通过动态代理实现横切关注点 | |
| 模板方法模式 | 消除重复代码 | JdbcTemplate、RestTemplate等模板类封装通用流程 |
| 观察者模式 | Spring 事件驱动模型(ApplicationEvent和ApplicationListener) | |
| 适配器模式 | 统一接口,兼容不同实现 | |
| 装饰者模式 | 增强其行为 | HttpServletRequestWapper包装HTTP请求 |
| 策略模式 | Spring MVC的HandelerMapping根据请求【匹配不同策略的处理器 | |
| 委派模式 | DispatcherServlet 将请求分发给不同的处理器(Controller或Handler) | |
| 建造者模式 | 分布构建复杂对象 | |
| 责任链模式 | Spring Security的过滤器FilterChainProxy,每个过滤器依次处理请求 |
Spring AOP使用
@Primary和@Qualifier注解的作用
| @Primary | 标记某个Bean为默认首选的候选对象。当存在多个相同类型的Bean时,Spring会优先选择带有@primary注解的Bean进行注入 |
| @Qualifier | 通过显式指定Bean的名称或标识来解决多个同类型Bean的冲突 |
@RequestBody和@ResponseBody注解的作用
| @ResquestBody | 用于将HTTP请求体中的内容绑定到方法的参数上,主要作用在方法的参数上 |
| @ResponseBody | 用于将方法的返回值直接写入HTTP相应体重,可以标注在方法或类上 |
springboot启动过程
- 本文标签: Spring Boot
- 本文链接: http://119.91.109.247:8443//article/125
- 版权声明: 本文由张亚东原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权