原创

SpringBoot面试题

温馨提示:
本文最后更新于 2025年08月21日,已超过 296 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

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是否能解决循环依赖

在一定程度上可以。

  1. Spring创建A时,发现它依赖B,但B被标记位@Lazy
  2. 不立即初始化B,而是注入一个B的代理对象(Spring动态生成)
  3. 当A的方法首次调用b.xx()时,代理对象才会触发B的实际初始化
  4. 此时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容器

  1. 在构建文件(Maven的pom.xml)中,从spring-boot-starter-web中排除默认的Tomcat依赖(spring-boot-starter-tomcat)
  2. 添加需要使用的容器依赖(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<ErrorResponse> handleBusinessException(BusinessException ex) {
        ErrorResponse error = new ErrorResponse(ex.getCode(), ex.getMessage());
        return ResponseEntity.status(ex.getHttpStatus()).body(error);
    }

    // 处理所有未捕获的异常
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> 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());
    }
}


解决方法:

  1. 分布式锁
  2. 分布式任务调度工具,如 XXL_JOB

项目统一返回结果

code:状态码,遵循HTTP状态码规范并拓展因为状态码

message:对状态的描述信息

data:实际返回的业务数据

timestamp:响应时间戳

  • 手动显示封装
    @GetMapping("/{id}")
    public Result<User> getUser(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return Result.success(user);
    }
  •  自动封装
@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 判断是否需要包装
        return !returnType.getParameterType().equals(Result.class);
    }
    
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
            Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return Result.success(body);
    }
}


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<String> 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实现异步处理

  1. 使用 @Async注解
  2. 使用ConpletableFuture
  3. 使用@Scheduled注解
  4. 使用线程池

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启动过程

正文到此结束