Appearance
Spring 面试题
Spring 基础
Q1: Spring 框架的核心模块有哪些?
┌─────────────────────────────────────────────────────────────────┐
│ Spring 核心模块 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Spring Core │
│ ├── Core - IoC 容器、依赖注入 │
│ ├── Context - 事件机制、资源加载 │
│ └── Beans - BeanFactory 核心 │
│ │
│ Spring AOP │
│ └── 面向切面编程、事务管理 │
│ │
│ Spring MVC │
│ └── Web 请求处理、视图解析 │
│ │
│ Spring Data │
│ ├── JDBC │
│ ├── ORM (Hibernate/JPA) │
│ └── Nosql (Redis/MongoDB) │
│ │
└─────────────────────────────────────────────────────────────────┘答案:
- Core Container:IoC/DI 核心模块
- AOP:面向切面编程
- MVC:Web 层框架
- DAO:JDBC 封装
- ORM:对象关系映射
- Context:应用上下文
- Web:Web 支持模块
Q2: 什么是 Spring IoC 容器?
答案: IoC(Inversion of Control,控制反转)是 Spring 的核心。
原理:
- 控制反转:对象的创建和管理由容器负责,而不是应用代码
- 依赖注入:容器在运行期将依赖关系注入到对象中
java
// 传统方式:应用代码自己创建对象
UserService service = new UserService();
// IoC 方式:容器创建对象并注入
// 容器:UserService service = new UserService();
// service.setUserRepository(userRepository);IoC 容器的好处:
- 降低对象间的耦合度
- 便于单元测试(可以用 Mock 对象)
- 对象的生命周期由容器管理
Q3: BeanFactory 和 ApplicationContext 的区别?
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 初始化 | 延迟加载 | 预加载 |
| 功能 | 基础功能 | 更强大(事件、国际化等) |
| 自动装配 | 支持 | 支持 |
| BeanPostProcessor | 需手动注册 | 自动注册 |
| 国际化 | 不支持 | 支持 |
| Web 应用 | 不适用 | 支持 |
答案:
java
// BeanFactory - 延迟加载,第一次 getBean 时才创建
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
UserService service = factory.getBean("userService");
// ApplicationContext - 预加载,启动时就创建所有单例 Bean
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService service = ctx.getBean("userService");实际开发中:通常使用 ApplicationContext。
Q4: Spring Bean 的生命周期?
┌─────────────────────────────────────────────────────────────────┐
│ Bean 生命周期 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 实例化 (Instantiation) │
│ ↓ │
│ 2. 属性赋值 (Populate Properties) │
│ ↓ │
│ 3. BeanNameAware │
│ ↓ │
│ 4. BeanFactoryAware / ApplicationContextAware │
│ ↓ │
│ 5. BeanPostProcessor.beforeInitialization │
│ ↓ │
│ 6. @PostConstruct / InitializingBean │
│ ↓ │
│ 7. BeanPostProcessor.afterInitialization │
│ ↓ │
│ 8. 使用中 │
│ ↓ │
│ 9. @PreDestroy / DisposableBean │
│ ↓ │
│ 10. 销毁 (Destruction) │
│ │
└─────────────────────────────────────────────────────────────────┘代码示例:
java
@Component
public class UserService implements BeanNameAware,
InitializingBean,
DisposableBean {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("Bean 名称:" + name);
}
@PostConstruct
public void init() {
System.out.println("@PostConstruct 初始化");
}
@Override
public void afterPropertiesSet() {
System.out.println("InitializingBean 初始化");
}
@PreDestroy
public void cleanup() {
System.out.println("@PreDestroy 销毁");
}
@Override
public void destroy() {
System.out.println("DisposableBean 销毁");
}
}Q5: Spring Bean 的作用域有哪些?
| 作用域 | 说明 | 是否需要 Web 环境 |
|---|---|---|
| singleton | 单例(默认),容器中只有一个实例 | 否 |
| prototype | 原型,每次获取创建新实例 | 否 |
| request | 每次 HTTP 请求创建一个实例 | 是 |
| session | 同一个 HTTP Session 共享一个实例 | 是 |
| application | 整个 Web 应用只有一个实例 | 是 |
| websocket | WebSocket 生命周期内只有一个实例 | 是 |
java
// 单例(默认)
@Scope("singleton")
// 原型:每次获取新实例
@Scope("prototype")
// request:每个请求一个实例
@Scope("request")
// session:每个会话一个实例
@Scope("session")面试点:
- 单例 Bean 是线程不安全的!
- 原型 Bean 的销毁需要手动处理
- 单例 Bean 依赖原型 Bean 时,原型 Bean 不会每次都创建新实例(需要用
@Lookup或ObjectFactory)
Spring Boot
Q6: Spring Boot 自动配置原理?
┌─────────────────────────────────────────────────────────────────┐
│ 自动配置执行流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. @SpringBootApplication 启动 │
│ ↓ │
│ 2. @EnableAutoConfiguration 启用自动配置 │
│ ↓ │
│ 3. SpringFactoriesLoader 加载 spring.factories │
│ ↓ │
│ 4. 根据 @Conditional 条件筛选配置类 │
│ ↓ │
│ 5. 通过 @Bean 注册组件 │
│ │
└─────────────────────────────────────────────────────────────────┘核心注解:
java
@SpringBootApplication
// 等价于:
@Configuration // 配置类
@EnableAutoConfiguration // 启用自动配置
@ComponentScan // 组件扫描spring.factories:
properties
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration条件注解:
@ConditionalOnClass- 类路径存在才配置@ConditionalOnMissingBean- 不存在 Bean 时才配置@ConditionalOnProperty- 配置属性满足条件才配置
Q7: Spring Boot 常用起步依赖(Starter)?
| Starter | 用途 |
|---|---|
| spring-boot-starter-web | Web 开发(Tomcat + Spring MVC) |
| spring-boot-starter-data-redis | Redis 支持 |
| spring-boot-starter-data-jpa | JPA 持久层 |
| spring-boot-starter-security | 安全认证 |
| spring-boot-starter-actuator | 应用监控 |
| spring-boot-starter-test | 单元测试 |
| spring-boot-starter-validation | 参数校验 |
Q8: Spring Boot 如何实现多环境配置?
方式1:多文件配置
application.yml # 公共配置
application-dev.yml # 开发环境
application-test.yml # 测试环境
application-prod.yml # 生产环境方式2:命令行指定
bash
java -jar app.jar --spring.profiles.active=prod方式3:IDEA 配置 在 Run Configuration 中设置 VM options: -Dspring.profiles.active=dev
Q9: @SpringBootApplication 做了哪些事?
java
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}等价于:
java
@Configuration // 标注为配置类
@EnableAutoConfiguration // 启用自动配置
@ComponentScan // 组件扫描(默认扫描当前包及其子包)exclude 属性:
java
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})Spring MVC
Q10: Spring MVC 请求处理流程?
┌─────────────────────────────────────────────────────────────────┐
│ Spring MVC 请求处理流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 请求 ──→ DispatcherServlet │
│ ↓ │
│ HandlerMapping 查找 Handler │
│ ↓ │
│ HandlerAdapter 执行 Handler │
│ ↓ │
│ 返回 ModelAndView │
│ ↓ │
│ ViewResolver 解析视图 │
│ ↓ │
│ View 渲染视图 │
│ ↓ │
│ 响应 │
│ │
└─────────────────────────────────────────────────────────────────┘Q11: @Controller 和 @RestController 的区别?
java
// 普通 Controller
@Controller
public class UserController {
@RequestMapping("/user")
public String getUser(Model model) {
model.addAttribute("user", user);
return "userDetail"; // 返回视图名
}
}
// REST Controller
@RestController
@RequestMapping("/api/users")
public class UserApiController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUser(id); // 直接返回数据
}
}区别:
@RestController = @Controller + @ResponseBody@Controller返回视图(JSP/Freemarker)@RestController返回 JSON/XML 数据
Q12: @RequestMapping 的常用属性?
java
@RestController
@RequestMapping("/api/users")
public class UserController {
@RequestMapping(
value = "/{id}",
method = RequestMethod.GET, // 请求方法
params = "version=1", // 请求参数
headers = "Content-Type=application/json", // 请求头
consumes = "application/json", // 消费的内容类型
produces = "application/json" // 生产的内容类型
)
public User getUser(@PathVariable Long id) {
return userService.getUser(id);
}
// 简写形式
@GetMapping("/{id}") // GET 请求
@PostMapping // POST 请求
@PutMapping("/{id}") // PUT 请求
@DeleteMapping("/{id}") // DELETE 请求
}Q13: Spring MVC 参数绑定的注解有哪些?
java
@GetMapping("/user")
public User getUser(
@PathVariable Long id, // 路径参数
@RequestParam String name, // 请求参数
@RequestParam(defaultValue = "10") int pageSize, // 默认值
@RequestParam(required = false) String email, // 可选参数
@RequestHeader String authorization, // 请求头
@CookieValue("JSESSIONID") String sessionId, // Cookie
@RequestBody User user, // 请求体(JSON)
@ModelAttribute User user // 表单参数
) { ... }Q14: Spring MVC 如何做参数校验?
步骤1:添加依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>步骤2:在实体类上加校验注解
java
public class UserRequest {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度3-20")
private String name;
@NotNull(message = "年龄不能为空")
@Min(value = 0, message = "年龄最小0")
@Max(value = 150, message = "年龄最大150")
private Integer age;
@Email(message = "邮箱格式不正确")
private String email;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
}步骤3:Controller 接收校验
java
@PostMapping
public User createUser(@Valid @RequestBody UserRequest request) {
// 校验失败会抛出 MethodArgumentNotValidException
return userService.createUser(request);
}步骤4:全局异常处理
java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleValidException(MethodArgumentNotValidException e) {
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return Result.error(400, message);
}
}Q15: Spring MVC 拦截器(Interceptor)和 Filter 的区别?
| 对比 | Filter | Interceptor |
|---|---|---|
| 来源 | Servlet 规范 | Spring MVC |
| 作用范围 | 所有请求 | Spring MVC 请求 |
| 配置位置 | web.xml / @WebFilter | @Configuration |
| 执行顺序 | FilterChain | HandlerInterceptor |
| 能否获取 Spring Bean | 不能(需通过 Servlet) | 能 |
Filter 示例:
java
@WebFilter("/*")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 前置处理
HttpServletRequest req = (HttpServletRequest) request;
System.out.println("Filter: " + req.getRequestURI());
chain.doFilter(request, response); // 继续执行
// 后置处理
}
}Interceptor 示例:
java
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 前置处理
String token = request.getHeader("Authorization");
if (token == null || !tokenService.validate(token)) {
response.setStatus(401);
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) {
// 后置处理
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
// 整个请求完成后
}
}Spring 事务
Q16: Spring 事务的隔离级别?
| 隔离级别 | 说明 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|---|
| DEFAULT | 使用数据库默认 | - | - | - |
| READ_UNCOMMITTED | 未提交读 | ✅ | ✅ | ✅ |
| READ_COMMITTED | 已提交读 | ❌ | ✅ | ✅ |
| REPEATABLE_READ | 可重复读 | ❌ | ❌ | ✅ |
| SERIALIZABLE | 串行化 | ❌ | ❌ | ❌ |
java
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateUser(User user) {
// 事务处理
}Q17: Spring 事务的传播行为?
| 传播行为 | 说明 |
|---|---|
| REQUIRED | 如果当前有事务,加入该事务(默认) |
| REQUIRES_NEW | 开启新事务,挂起当前事务 |
| SUPPORTS | 如果当前有事务,加入该事务 |
| NOT_SUPPORTED | 不使用事务,挂起当前事务 |
| MANDATORY | 必须在事务中执行,否则抛异常 |
| NEVER | 必须在非事务中执行,否则抛异常 |
| NESTED | 嵌套事务(Savepoint) |
示例:
java
@Transactional
public void outerMethod() {
// 这是一个事务
innerMethod(); // 默认 REQUIRED,会加入当前事务
innerMethod2(); // REQUIRES_NEW,会开启新事务
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod2() {
// 这是另一个独立的事务
}Q18: @Transactional 失效的场景?
1. 方法内部调用
java
@Service
public class UserService {
public void outer() {
// ❌ 失效!this.inner() 没有经过代理对象
this.inner();
}
@Transactional
public void inner() {
// 不会开启事务
}
}
// ✅ 正确做法
@Autowired
private UserService self;
public void outer() {
self.inner();
}2. 异常被 catch 吞掉
java
@Transactional
public void update() {
try {
doSomething();
} catch (Exception e) {
// ❌ 异常被吞掉,事务不会回滚
}
}3. 非 public 方法
java
// ❌ 失效
@Transactional
private void update() { }
// ✅ 正确
@Transactional
public void update() { }4. rollbackFor 配置错误
java
// 默认只对 RuntimeException 回滚
@Transactional
public void update() {
throw new IOException(); // ❌ 不会回滚
}
// ✅ 指定回滚异常
@Transactional(rollbackFor = Exception.class)
public void update() throws IOException {
throw new IOException(); // ✅ 会回滚
}5. 多数据源
java
// @Transactional 默认作用于主数据源
// 如果操作从数据源,需要指定
@Transactional(transactionManager = "txManager2")
public void updateSlave() { }Spring 疑难
Q19: Spring 如何解决循环依赖?
┌─────────────────────────────────────────────────────────────────┐
│ 循环依赖示意 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ A → @Autowired B │
│ B → @Autowired A │
│ │
│ Spring 通过三级缓存解决: │
│ │
│ singletonObjects ─── 一级缓存(成品Bean) │
│ earlySingletonObjects ─── 二级缓存(早期Bean) │
│ singletonFactories ─── 三级缓存(BeanFactory) │
│ │
└─────────────────────────────────────────────────────────────────┘解决过程:
- 创建 A,发现依赖 B,尝试从三级缓存获取 B 的 ObjectFactory
- 创建 B,发现依赖 A,尝试从三级缓存获取 A 的 ObjectFactory
- A 从三级缓存获取到 ObjectFactory,创建早期 A(未填充属性)
- B 获取到早期 A,填充属性,创建完成
- A 获取到完成的 B,填充属性,创建完成
不能解决的情况:
@Prototype作用域的 Bean- 构造函数注入的循环依赖
@Async注解的 Bean
Q20: Spring AOP 的实现原理?
┌─────────────────────────────────────────────────────────────────┐
│ AOP 代理实现 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Spring AOP │
│ │ │
│ ├── JDK 动态代理(目标类实现接口) │
│ │ └── Proxy.newProxyInstance() │
│ │ │
│ └── CGLIB 代理(目标类没实现接口) │
│ └── Enhancer.create() │
│ │
└─────────────────────────────────────────────────────────────────┘示例:
java
@Component
@Aspect
public class LogAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void pointcut() { }
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
// 前置通知
System.out.println("方法执行前");
Object result = joinPoint.proceed(); // 执行目标方法
// 后置通知
long end = System.currentTimeMillis();
System.out.println("方法执行后,耗时:" + (end - start) + "ms");
return result;
}
@Before("pointcut()")
public void before() {
System.out.println("前置通知");
}
@AfterReturning(pointcut = "pointcut()", returning = "result")
public void afterReturning(Object result) {
System.out.println("返回通知:" + result);
}
@AfterThrowing(pointcut = "pointcut()", throwing = "e")
public void afterThrowing(Exception e) {
System.out.println("异常通知:" + e.getMessage());
}
}Q21: Spring Cloud 和 Spring Boot 的关系?
| 对比 | Spring Boot | Spring Cloud |
|---|---|---|
| 功能 | 快速构建应用 | 分布式系统解决方案 |
| 定位 | 单体应用 | 微服务架构 |
| 依赖 | 基础框架 | 整合多个组件 |
| 关系 | Spring Boot 是 Spring Cloud 的基础 |
Spring Boot + Spring Cloud 组合:
┌─────────────────────────────────────────────────────────────────┐
│ 微服务技术栈 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Spring Boot - 快速开发单个微服务 │
│ │ │
│ ├── 服务开发 (Spring MVC / WebFlux) │
│ ├── 服务注册与发现 (Nacos / Eureka) │
│ ├── 服务调用 (OpenFeign / Dubbo) │
│ ├── 负载均衡 (Ribbon / LoadBalancer) │
│ ├── 熔断器 (Sentinel / Hystrix) │
│ ├── 网关 (Gateway) │
│ ├── 配置中心 (Nacos Config / Spring Cloud Config) │
│ └── 消息总线 (Spring Cloud Bus) │
│ │
└─────────────────────────────────────────────────────────────────┘总结
Spring 高频面试知识点:
| 知识点 | 面试频率 |
|---|---|
| IoC/DI 原理 | ⭐⭐⭐⭐⭐ |
| Bean 生命周期 | ⭐⭐⭐⭐ |
| Spring Boot 自动配置 | ⭐⭐⭐⭐⭐ |
| @Transactional 失效场景 | ⭐⭐⭐⭐⭐ |
| 事务隔离级别和传播行为 | ⭐⭐⭐⭐ |
| Spring MVC 请求处理流程 | ⭐⭐⭐⭐ |
| 循环依赖解决方案 | ⭐⭐⭐⭐ |
| AOP 原理和实现 | ⭐⭐⭐⭐ |