DukeDuke
主页
项目文档
技术文档
  • 单机版
  • 微服务
  • 代办项目
  • 优鲜项目
项目管理
关于我们
主页
项目文档
技术文档
  • 单机版
  • 微服务
  • 代办项目
  • 优鲜项目
项目管理
关于我们
  • 技术文档

    • 网络原理

      • 交换机
      • 路由器
      • TCP/IP协议
      • HTTP 与 HTTPS
    • 软件架构

      • 什么是软件架构
      • 分层架构
      • 微服务架构
      • 事件驱动架构
      • 领域驱动设计(DDD)
      • 架构图
      • 高并发系统
    • Vue3

      • Vue3简介
      • Vue3响应式系统
      • Vue3组合式API
      • Vue3生命周期
      • Vue3模板语法
      • Vue3组件系统
      • Vue3 路由系统
      • Vue3 状态管理
      • Vue3 性能优化
      • Vue3 TypeScript 支持
      • Vue3 项目实战
      • VUE 面试题大全
      • Node.js 安装
    • JAVA

      • JVM

        • 认识JVM
        • JVM类加载器
        • 运行时数据区
        • 执行引擎
        • 本地方法接口
        • 本地方法库
        • JVM垃圾回收
        • JVM性能监控
        • JVM调优
      • 设计模式
        • 单例模式
        • 工厂模式
        • 策略模式
        • 适配器模式
        • 建造者模式
        • 原型模式
        • 装饰器模式
        • 代理模式
        • 外观模式
        • 享元模式
        • 组合模式
        • 桥接模式
      • Java多线程

        • Java 线程基础详解
        • Java 线程池详解
        • Java ThreadLocal 详解
        • Java volatile 详解
        • Java 线程间通信详解
        • Java 线程安全详解
        • Java 线程调度详解
        • Java 线程优先级详解

        • Java 线程中断详解
        • Java 线程死锁详解
      • Java反射
      • Java 面试题

        • Java 基础概念面试题
        • Java 面向对象编程面试题
        • Java 集合框架面试题
        • Java 多线程与并发面试题
        • JVM 与内存管理面试题
        • Java I/O 与 NIO 面试题
        • Java 异常处理面试题
        • Java 反射与注解面试题
        • Java Spring 框架面试题
        • Java 数据库与 JDBC 面试题
        • Java 性能优化面试题
        • Java 实际项目经验面试题
        • Java 高级特性面试题
        • Java 面试准备建议
    • Python

      • Python简介
      • Python安装
      • Python hello world
      • Python基础语法
      • Python数据类型
      • Python数字
      • Python字符串
      • Python列表
      • Python元组
      • Python字典
      • Python日期时间
      • Python文件操作
      • Python异常处理
      • Python函数
      • Python类
      • Python模块
      • Python包
      • Python多线程
      • Python面向对象
      • Python爬虫
      • Django web框架
      • Python 面试题

        • Python 面试题导航
        • Python 基础概念
        • Python 面向对象编程
        • Python 数据结构
        • Python 高级特性
        • Python 框架
        • Python 性能优化
        • Python 项目经验
    • Spring

      • Spring
      • Springboot
      • Spring Security 安全框架
      • SpringBoot 中的事件详解
      • SpringBoot 中的定时任务详解
      • SpringBoot 自动装配原理与源码解释
    • Mybatis

      • Mybatis
      • Mybatis-Plus
    • 数据库

      • Redis

        • Redis简介
        • Redis(单机)安装
        • Redis配置
        • Redis数据结构
        • RDB、AOF 和混合持久化机制
        • Redis内存管理
        • Redis缓存一致性
        • Redis缓存穿透
        • Redis缓存击穿
        • Redis缓存雪崩
        • Redis Lua脚本
        • Redis主从复制
        • Redis哨兵模式
        • Redis集群
        • Redis数据分片
        • Redis CPU使用率过高
        • Redis面试题
      • MySQL

        • MySQL简介
        • MySQL安装
        • MySQL配置
        • MYSQL日常维护
        • MYSQL优化-慢查询
        • MYSQL优化-索引
        • MYSQL数据库设计规范
    • 消息队列

      • RocketMQ
      • Kafka
      • RabbitMQ
      • 消息队列面试题
    • 微服务

      • SpringCloud 微服务
      • Eureka 注册中心
      • Nacos 注册中心
      • Gateway 网关
      • Feign 服务调用
      • Sentinel 限流 与 熔断
      • Seata 分布式事务
      • CAP 理论
      • Redis 分布式锁
      • 高并发系统设计
    • ELK日志分析系统

      • Elasticsearch 搜索引擎
      • Logstash 数据处理
      • Kibana 可视化
      • ELK 实战
    • 开放API

      • 开放API设计
      • 开放API示例项目
    • 人工智能

      • 人工智能简介
      • 机器学习

      • 深度学习

      • 自然语言处理

      • 计算机视觉

        • CUDA与cuDNN详细安装
        • Conda 安装
        • Pytorch 深度学习框架
        • yolo 目标检测
        • TensorRT 深度学习推理优化引擎
        • TensorFlow 机器学习
        • CVAT 图像标注
        • Windows 下安装 CUDA、cuDNN、TensorRT、TensorRT-YOLO 环境
        • Windows10+CUDA+cuDNN+TensorRT+TensorRT-YOLO 部署高性能YOLO11推理
    • 大数据

      • 大数据简介
      • Hadoop 数据存储
      • Flume 数据采集
      • Sqoop 数据导入导出
      • Hive 数据仓库
      • Spark 数据处理
      • Flink 数据处理
      • Kafka 数据采集
      • HBase 数据存储
      • Elasticsearch 搜索引擎
    • 图像处理

      • 图像处理简介
      • 医学图像web呈现
      • 医学图像处理
      • 切片细胞分离问题
    • 服务器&运维

      • Linux 系统

        • Linux 系统管理
        • Linux 网络管理
        • Linux 文件管理
        • Linux 命令大全
      • Nginx Web 服务器

        • Nginx 安装 与 配置
        • Nginx 负载均衡
        • Nginx SSL证书配置
        • Nginx Keepalived 高可用
      • Docker 容器

        • Docker 简介
        • Docker 安装与配置
        • Docker 命令
        • Docker 部署 Nginx
        • Docker 部署 MySQL
        • Docker 部署 Redis
      • 服务器

        • 塔式服务器
        • 机架式服务器
        • 刀片服务器
      • Git 版本控制
      • Jenkins 持续集成
      • Jmeter 性能测试
      • Let's Encrypt 免费SSL证书
    • 简历

      • 项目经理简历
      • 开发工程师简历

Spring Framework 面试与学习指南

1. Spring Framework 简介

Spring Framework 是一个开源的 Java 平台,为开发企业级 Java 应用提供全面的基础设施支持。Spring 以其依赖注入(DI)和面向切面编程(AOP)等核心特性而闻名。

1.1 Spring Framework 的优势

  • 轻量级:框架本身的代码量小,对应用的影响最小
  • 控制反转(IoC):通过依赖注入实现松耦合,提高代码可测试性
  • 面向切面编程(AOP):允许将横切关注点与业务逻辑分离
  • 容器:管理应用中的对象的配置和生命周期
  • 框架集成:易于与其他框架集成(如 Hibernate、MyBatis 等)
  • 事务管理:统一的事务管理接口,支持声明式和编程式事务
  • MVC 框架:用于开发灵活、松耦合的 Web 应用

1.2 Spring 生态体系

Spring Framework (核心)
├── Spring Boot (快速开发)
├── Spring Cloud (微服务)
├── Spring Security (安全)
├── Spring Data (数据访问)
└── Spring Batch (批处理)

2. 核心特性详解

2.1 依赖注入(DI)

依赖注入是 Spring 框架最核心的特性之一,它有助于实现松耦合的应用设计。

2.1.1 三种注入方式

1. 构造器注入(推荐)

@Component
public class UserService {
    private final UserRepository userRepository;
    private final EmailService emailService;

    @Autowired // 可以省略,Spring 4.3+ 支持隐式注入
    public UserService(UserRepository userRepository, EmailService emailService) {
        this.userRepository = userRepository;
        this.emailService = emailService;
    }
}

2. Setter 注入

@Component
public class UserService {
    private UserRepository userRepository;
    private EmailService emailService;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Autowired
    public void setEmailService(EmailService emailService) {
        this.emailService = emailService;
    }
}

3. 字段注入(不推荐)

@Component
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private EmailService emailService;
}

2.1.2 面试常见问题

Q: 为什么推荐使用构造器注入? A:

  • 保证依赖不可变性(final 修饰)
  • 确保必要的依赖在对象创建时就被注入
  • 便于单元测试
  • 避免循环依赖问题

Q: @Autowired 和 @Resource 的区别? A:

  • @Autowired 是 Spring 提供的注解,默认按类型注入
  • @Resource 是 JSR-250 规范,默认按名称注入
  • @Autowired 可以配合 @Qualifier 指定名称
  • @Resource 可以通过 name 属性指定名称

2.2 Spring Bean

Spring Bean 是被 Spring 容器管理的对象。

2.2.1 Bean 作用域

@Component
@Scope("singleton") // 默认作用域
public class SingletonBean {}

@Component
@Scope("prototype")
public class PrototypeBean {}

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestBean {}

@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionBean {}

作用域说明:

  • singleton(默认):每个 Spring IoC 容器仅创建一个实例
  • prototype:每次请求都会创建新的实例
  • request:每个 HTTP 请求都会创建新的实例
  • session:每个 HTTP 会话都会创建新的实例
  • application:ServletContext 生命周期内只有一个实例
  • websocket:WebSocket 会话生命周期内只有一个实例

2.2.2 Bean 生命周期详解

Spring Bean 的实例化过程包含以下几个关键步骤:

1. 实例化 (Instantiation)
   ↓
2. 属性注入 (Population)
   ↓
3. Aware 接口回调
   ↓
4. BeanPostProcessor 前置处理
   ↓
5. 初始化 (Initialization)
   ↓
6. BeanPostProcessor 后置处理
   ↓
7. Bean 就绪 (Ready)
   ↓
8. 销毁 (Destruction) - 容器关闭时

详细生命周期示例:

@Component
public class LifecycleBean implements BeanNameAware, BeanFactoryAware,
                                   InitializingBean, DisposableBean {

    private String beanName;
    private BeanFactory beanFactory;

    public LifecycleBean() {
        System.out.println("1. 构造方法执行");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("5. @PostConstruct 执行");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("3. BeanNameAware 回调: " + name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("3. BeanFactoryAware 回调");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("6. InitializingBean.afterPropertiesSet() 执行");
    }

    public void customInit() {
        System.out.println("6. 自定义初始化方法执行");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("8. @PreDestroy 执行");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("8. DisposableBean.destroy() 执行");
    }

    public void customDestroy() {
        System.out.println("8. 自定义销毁方法执行");
    }
}

面试常见问题:

Q: Bean 的生命周期中,哪些是必须的? A: 只有实例化和属性注入是必须的,其他步骤都是可选的。

Q: BeanPostProcessor 的作用是什么? A: BeanPostProcessor 是 Spring 提供的扩展点,可以在 Bean 初始化前后进行自定义处理,常用于 AOP 代理的创建。

Q: 如何自定义 Bean 的初始化方法? A: 可以通过 @PostConstruct 注解、实现 InitializingBean 接口,或在 XML 中配置 init-method 属性。

2.3 循环依赖问题

2.3.1 循环依赖的解决方案

Spring 通过三级缓存解决循环依赖:

@Service
public class AService {
    @Autowired
    private BService bService;

    public void methodA() {
        bService.methodB();
    }
}

@Service
public class BService {
    @Autowired
    private AService aService;

    public void methodB() {
        aService.methodA();
    }
}

三级缓存机制:

  • 一级缓存:singletonObjects - 存放完全初始化好的 Bean
  • 二级缓存:earlySingletonObjects - 存放早期暴露的 Bean(未完全初始化)
  • 三级缓存:singletonFactories - 存放 Bean 的工厂对象

2.3.2 面试常见问题

Q: Spring 如何解决循环依赖? A: Spring 通过三级缓存机制解决循环依赖:

  1. 创建 A 的实例,放入三级缓存
  2. 注入 B 时,发现 B 不存在,创建 B 的实例
  3. B 注入 A 时,从三级缓存中获取 A 的早期引用
  4. B 创建完成,放入一级缓存
  5. A 继续完成初始化,放入一级缓存

Q: 构造器注入的循环依赖能解决吗? A: 不能。Spring 只能解决 setter 注入和字段注入的循环依赖,构造器注入的循环依赖无法解决。

3. Spring IoC 容器

IoC 容器是 Spring 框架的核心。它负责管理对象的创建、配置和组装。

3.1 配置方式对比

3.1.1 XML 配置(传统方式)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.example"/>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 开启事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

3.1.2 Java 配置(推荐)

@Configuration
@ComponentScan("com.example")
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
public class AppConfig {

    @Value("${db.driver}")
    private String driverClassName;

    @Value("${db.url}")
    private String jdbcUrl;

    @Value("${db.username}")
    private String username;

    @Value("${db.password}")
    private String password;

    @Bean
    public DataSource dataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setJdbcUrl(jdbcUrl);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

3.1.3 注解配置(最常用)

@SpringBootApplication
@EnableTransactionManagement
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@Service
@Transactional
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Cacheable("users")
    public User findById(Long id) {
        return userRepository.findById(id);
    }
}

3.2 面试常见问题

Q: @Configuration 和 @Component 的区别? A:

  • @Configuration 标识的类会被 CGLIB 增强,确保 @Bean 方法返回单例
  • @Component 是普通的组件注解,不会被增强
  • @Configuration 类中的 @Bean 方法可以相互调用

Q: @ComponentScan 的作用是什么? A: @ComponentScan 用于扫描指定包下的组件,将带有 @Component、@Service、@Repository、@Controller 注解的类注册为 Spring Bean。

Q: 如何排除某些 Bean 的自动装配? A: 可以使用 @ConditionalOnMissingBean、@ConditionalOnProperty 等条件注解,或者在 @ComponentScan 中使用 excludeFilters。

4. Spring AOP

AOP(面向切面编程)允许将横切关注点(如日志、事务、安全等)与业务逻辑分离。

4.1 AOP 核心概念

  • Aspect(切面):横切关注点的模块化
  • Join point(连接点):程序执行过程中的某个特定点
  • Pointcut(切入点):匹配连接点的表达式
  • Advice(通知):在切入点执行的代码
  • Target Object(目标对象):被代理的对象
  • Proxy(代理):AOP 框架创建的对象

4.2 通知类型

@Aspect
@Component
public class LoggingAspect {

    // 前置通知:在目标方法执行前执行
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("方法 " + methodName + " 开始执行");
    }

    // 后置通知:在目标方法执行后执行(无论是否异常)
    @After("execution(* com.example.service.*.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("方法 " + methodName + " 执行完成");
    }

    // 返回通知:在目标方法正常返回后执行
    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))",
                    returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("方法 " + methodName + " 返回结果: " + result);
    }

    // 异常通知:在目标方法抛出异常后执行
    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))",
                   throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("方法 " + methodName + " 抛出异常: " + ex.getMessage());
    }

    // 环绕通知:在目标方法执行前后都执行
    @Around("execution(* com.example.service.*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        long startTime = System.currentTimeMillis();

        try {
            Object result = joinPoint.proceed();
            long endTime = System.currentTimeMillis();
            System.out.println("方法 " + methodName + " 执行时间: " + (endTime - startTime) + "ms");
            return result;
        } catch (Exception e) {
            System.out.println("方法 " + methodName + " 执行异常");
            throw e;
        }
    }
}

4.3 切入点表达式

@Aspect
@Component
public class PointcutExamples {

    // 匹配所有 public 方法
    @Pointcut("execution(public * *(..))")
    public void publicMethods() {}

    // 匹配特定包下的所有方法
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}

    // 匹配带有特定注解的方法
    @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
    public void transactionalMethods() {}

    // 匹配特定参数类型的方法
    @Pointcut("execution(* *(String, int))")
    public void stringIntMethods() {}

    // 组合切入点
    @Pointcut("serviceMethods() && publicMethods()")
    public void publicServiceMethods() {}

    @Before("publicServiceMethods()")
    public void beforePublicService() {
        System.out.println("执行公共服务方法");
    }
}

4.4 面试常见问题

Q: Spring AOP 的代理方式有哪些? A:

  • JDK 动态代理:基于接口的代理,目标类必须实现接口
  • CGLIB 代理:基于继承的代理,可以代理没有实现接口的类
  • Spring 默认优先使用 JDK 动态代理,如果目标类没有实现接口则使用 CGLIB

Q: AOP 的底层原理是什么? A: AOP 的底层原理是动态代理:

  1. 在运行时动态创建代理对象
  2. 代理对象拦截目标方法的调用
  3. 在方法调用前后执行切面逻辑

Q: @Aspect 和 @Component 的区别? A: @Aspect 标识这是一个切面类,@Component 标识这是一个 Spring 组件。通常两者结合使用,让切面类被 Spring 容器管理。

5. Spring MVC

Spring MVC 是一个用于构建 Web 应用的框架,它实现了 MVC 设计模式。

5.1 Spring MVC 核心组件

HTTP 请求
    ↓
DispatcherServlet (前端控制器)
    ↓
HandlerMapping (处理器映射)
    ↓
HandlerAdapter (处理器适配器)
    ↓
Controller (控制器)
    ↓
ViewResolver (视图解析器)
    ↓
View (视图)
    ↓
HTTP 响应

5.2 控制器开发

@Controller
@RequestMapping("/api/users")
@Validated
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    // GET 请求 - 获取用户列表
    @GetMapping
    public ResponseEntity<List<User>> getUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        List<User> users = userService.findAll(page, size);
        return ResponseEntity.ok(users);
    }

    // GET 请求 - 获取单个用户
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        if (user == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(user);
    }

    // POST 请求 - 创建用户
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
        User createdUser = userService.create(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }

    // PUT 请求 - 更新用户
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id,
                                         @Valid @RequestBody User user) {
        User updatedUser = userService.update(id, user);
        if (updatedUser == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(updatedUser);
    }

    // DELETE 请求 - 删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        boolean deleted = userService.delete(id);
        if (!deleted) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.noContent().build();
    }

    // 异常处理
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
        ErrorResponse error = new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }
}

5.3 数据绑定和验证

@Data
@Validated
public class User {
    @NotNull(message = "用户ID不能为空")
    private Long id;

    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 50, message = "用户名长度必须在2-50之间")
    private String username;

    @Email(message = "邮箱格式不正确")
    private String email;

    @Min(value = 0, message = "年龄不能为负数")
    @Max(value = 150, message = "年龄不能超过150")
    private Integer age;
}

@RestController
@RequestMapping("/api/users")
public class UserController {

    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody User user,
                                         BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            List<String> errors = bindingResult.getFieldErrors()
                .stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.toList());
            throw new ValidationException("验证失败: " + errors);
        }

        User createdUser = userService.create(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }
}

5.4 面试常见问题

Q: @Controller 和 @RestController 的区别? A:

  • @Controller 标识这是一个控制器,返回视图名称
  • @RestController 是 @Controller 和 @ResponseBody 的组合,直接返回数据

Q: Spring MVC 的请求处理流程是什么? A:

  1. 请求到达 DispatcherServlet
  2. DispatcherServlet 通过 HandlerMapping 找到对应的 Handler
  3. HandlerAdapter 调用 Handler 处理请求
  4. Handler 返回 ModelAndView
  5. ViewResolver 解析视图
  6. 渲染视图并返回响应

Q: 如何自定义异常处理? A: 可以使用 @ExceptionHandler 注解处理特定异常,或使用 @ControllerAdvice 创建全局异常处理器。

6. Spring 事务管理

Spring 提供了一致的事务管理抽象,支持声明式事务和编程式事务。

6.1 事务传播行为

@Service
@Transactional
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private OrderService orderService;

    // REQUIRED(默认):支持当前事务,如果不存在则创建新事务
    @Transactional(propagation = Propagation.REQUIRED)
    public void createUser(User user) {
        userRepository.save(user);
        // 如果这里抛出异常,整个事务回滚
    }

    // REQUIRES_NEW:总是创建新事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void createUserInNewTransaction(User user) {
        userRepository.save(user);
        // 即使外层事务回滚,这个事务也会提交
    }

    // SUPPORTS:支持当前事务,如果不存在则以非事务方式执行
    @Transactional(propagation = Propagation.SUPPORTS)
    public User findUser(Long id) {
        return userRepository.findById(id);
    }

    // NOT_SUPPORTED:以非事务方式执行
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void sendEmail(String email) {
        // 发送邮件,不参与事务
    }

    // MANDATORY:必须在事务中执行,否则抛出异常
    @Transactional(propagation = Propagation.MANDATORY)
    public void updateUser(User user) {
        userRepository.save(user);
    }

    // NEVER:不能在事务中执行,否则抛出异常
    @Transactional(propagation = Propagation.NEVER)
    public void readOnlyOperation() {
        // 只读操作
    }

    // NESTED:如果存在事务则在嵌套事务中执行
    @Transactional(propagation = Propagation.NESTED)
    public void nestedOperation() {
        // 嵌套事务操作
    }
}

6.2 事务隔离级别

@Service
public class TransactionIsolationService {

    // 读未提交:允许脏读
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void readUncommitted() {
        // 可以读取其他事务未提交的数据
    }

    // 读已提交:防止脏读
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void readCommitted() {
        // 只能读取已提交的数据
    }

    // 可重复读:防止不可重复读
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public void repeatableRead() {
        // 在同一事务中多次读取同一数据,结果一致
    }

    // 串行化:最高隔离级别
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void serializable() {
        // 完全串行化执行,性能最低
    }
}

6.3 声明式事务

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private OrderRepository orderRepository;

    // 基本事务
    @Transactional
    public void createUser(User user) {
        userRepository.save(user);
    }

    // 只读事务
    @Transactional(readOnly = true)
    public User findUser(Long id) {
        return userRepository.findById(id);
    }

    // 指定超时时间
    @Transactional(timeout = 30)
    public void longRunningOperation() {
        // 30秒超时
    }

    // 指定回滚异常
    @Transactional(rollbackFor = {UserException.class, OrderException.class})
    public void createUserWithOrder(User user, Order order) {
        userRepository.save(user);
        orderRepository.save(order);
        // 如果抛出 UserException 或 OrderException,事务回滚
    }

    // 指定不回滚异常
    @Transactional(noRollbackFor = {ValidationException.class})
    public void createUserWithValidation(User user) {
        userRepository.save(user);
        // 如果抛出 ValidationException,事务不回滚
    }
}

6.4 编程式事务

6.4.1 使用 TransactionTemplate

@Service
public class UserService {

    private final TransactionTemplate transactionTemplate;
    private final UserRepository userRepository;

    public UserService(TransactionTemplate transactionTemplate, UserRepository userRepository) {
        this.transactionTemplate = transactionTemplate;
        this.userRepository = userRepository;
    }

    public void createUserWithTransaction(User user) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    userRepository.save(user);
                    // 其他业务逻辑
                } catch (Exception e) {
                    status.setRollbackOnly();
                    throw e;
                }
            }
        });
    }

    // 使用 Lambda 表达式的简化写法
    public void createUserWithLambda(User user) {
        transactionTemplate.execute(status -> {
            userRepository.save(user);
            return null;
        });
    }

    // 带返回值的事务
    public User createUserAndReturn(User user) {
        return transactionTemplate.execute(status -> {
            User savedUser = userRepository.save(user);
            return savedUser;
        });
    }
}

6.4.2 使用 PlatformTransactionManager

@Service
public class ComplexTransactionService {

    private final PlatformTransactionManager transactionManager;
    private final UserRepository userRepository;

    public ComplexTransactionService(PlatformTransactionManager transactionManager,
                                   UserRepository userRepository) {
        this.transactionManager = transactionManager;
        this.userRepository = userRepository;
    }

    public void complexTransaction(User user, Order order) {
        // 定义事务属性
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        def.setTimeout(30); // 30秒超时
        def.setReadOnly(false);

        TransactionStatus status = transactionManager.getTransaction(def);

        try {
            // 执行业务逻辑
            userRepository.save(user);
            // 其他操作...

            // 提交事务
            transactionManager.commit(status);
        } catch (Exception e) {
            // 回滚事务
            transactionManager.rollback(status);
            throw e;
        }
    }
}

6.5 面试常见问题

Q: 事务的 ACID 特性是什么? A:

  • 原子性(Atomicity):事务是不可分割的工作单位
  • 一致性(Consistency):事务执行前后数据保持一致
  • 隔离性(Isolation):并发事务之间相互隔离
  • 持久性(Durability):事务提交后数据永久保存

Q: 事务传播行为有哪些? A:

  • REQUIRED:支持当前事务,如果不存在则创建新事务
  • REQUIRES_NEW:总是创建新事务
  • SUPPORTS:支持当前事务,如果不存在则以非事务方式执行
  • NOT_SUPPORTED:以非事务方式执行
  • MANDATORY:必须在事务中执行
  • NEVER:不能在事务中执行
  • NESTED:如果存在事务则在嵌套事务中执行

Q: 事务隔离级别有哪些? A:

  • READ_UNCOMMITTED:读未提交,允许脏读
  • READ_COMMITTED:读已提交,防止脏读
  • REPEATABLE_READ:可重复读,防止不可重复读
  • SERIALIZABLE:串行化,最高隔离级别

Q: 声明式事务和编程式事务的区别? A:

  • 声明式事务:通过注解配置,代码侵入性小,推荐使用
  • 编程式事务:通过代码控制,灵活性高,适用于复杂场景
最近更新:: 2025/8/14 09:20
Contributors: Duke
Next
Springboot