Spring Framework 详细知识点文档
目录
- [Spring 概述与核心概念](#Spring 概述与核心概念 "#1-spring-%E6%A6%82%E8%BF%B0%E4%B8%8E%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5")
- [IoC 容器与依赖注入](#IoC 容器与依赖注入 "#2-ioc-%E5%AE%B9%E5%99%A8%E4%B8%8E%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5")
- [Bean 的配置与管理](#Bean 的配置与管理 "#3-bean-%E7%9A%84%E9%85%8D%E7%BD%AE%E4%B8%8E%E7%AE%A1%E7%90%86")
- [AOP 面向切面编程](#AOP 面向切面编程 "#4-aop-%E9%9D%A2%E5%90%91%E5%88%87%E9%9D%A2%E7%BC%96%E7%A8%8B")
- [Spring 事务管理](#Spring 事务管理 "#5-spring-%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86")
- [Spring MVC](#Spring MVC "#6-spring-mvc")
- [Spring Boot](#Spring Boot "#7-spring-boot")
- [Spring 数据访问](#Spring 数据访问 "#8-spring-%E6%95%B0%E6%8D%AE%E8%AE%BF%E9%97%AE")
- [Spring 注解大全](#Spring 注解大全 "#9-spring-%E6%B3%A8%E8%A7%A3%E5%A4%A7%E5%85%A8")
- [Spring 设计模式](#Spring 设计模式 "#10-spring-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F")
- 最佳实践与常见问题
1. Spring 概述与核心概念
1.1 什么是 Spring Framework?
Spring 是一个开源的轻量级 Java 开发框架,核心是简化企业级应用开发。创建于2003年,由 Rod Johnson 创立。
核心价值主张:
- 非侵入式:不强制继承特定类或实现特定接口
- 轻量级:完整的 Spring 框架可以压缩到 1MB 多的 JAR 文件
- 模块化:按需使用,不强制全部引入
1.2 Spring 模块组成
scss
Spring Framework Runtime
├── Core Container (核心容器)
│ ├── spring-core (核心工具类,基础模块)
│ ├── spring-beans (Bean的创建、配置、管理)
│ ├── spring-context (ApplicationContext,IoC容器)
│ ├── spring-expression (SpEL 表达式语言)
│ └── spring-context-support (第三方库集成支持)
│
├── AOP & Instrumentation
│ ├── spring-aop (基于代理的AOP实现)
│ ├── spring-aspects (AspectJ集成)
│ └── spring-instrument (类加载器实现)
│
├── Data Access/Integration
│ ├── spring-jdbc (JDBC抽象层)
│ ├── spring-tx (声明式事务管理)
│ ├── spring-orm (ORM框架集成)
│ ├── spring-oxm (Object/XML映射)
│ └── spring-jms (消息服务)
│
├── Web
│ ├── spring-web (基础Web功能)
│ ├── spring-webmvc (MVC框架)
│ ├── spring-websocket (WebSocket支持)
│ └── spring-webmvc-portlet (Portlet支持)
│
└── Test
└── spring-test (测试支持)
1.3 Spring 核心概念术语
- Bean:由 Spring IoC 容器管理的对象
- IoC (控制反转):将对象创建和依赖关系管理的控制权交给容器
- DI (依赖注入):IoC 的一种实现方式,容器在运行时动态注入依赖
- AOP (面向切面编程):将横切关注点与业务逻辑分离
- 容器:Spring 中负责管理 Bean 的生命周期和配置的核心组件
2. IoC 容器与依赖注入
2.1 IoC 实现原理
IoC 容器的工作流程:
markdown
1. 读取配置文件/注解
2. 根据配置元数据创建 Bean 定义 (BeanDefinition)
3. 实例化 Bean
4. 处理依赖注入
5. Bean 初始化 (init-method, InitializingBean接口)
6. Bean 就绪可用
7. 容器关闭时销毁 Bean (destroy-method, DisposableBean接口)
2.2 核心接口
java
// 1. BeanFactory - 最基础的 IoC 容器接口
public interface BeanFactory {
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType);
<T> T getBean(Class<T> requiredType);
boolean containsBean(String name);
boolean isSingleton(String name);
boolean isPrototype(String name);
Class<?> getType(String name);
}
// 2. ApplicationContext - 企业级应用上下文
public interface ApplicationContext extends
EnvironmentCapable,
ListableBeanFactory,
HierarchicalBeanFactory,
MessageSource, // 国际化
ApplicationEventPublisher, // 事件发布
ResourcePatternResolver { // 资源加载
// 继承了多个接口,功能更全面
}
// 3. 常用实现类
// - ClassPathXmlApplicationContext (基于XML,类路径)
// - FileSystemXmlApplicationContext (基于XML,文件系统)
// - AnnotationConfigApplicationContext (基于Java配置)
// - WebApplicationContext (Web环境专用)
2.3 依赖注入方式
2.3.1 构造器注入(推荐)
java
@Component
public class UserService {
private final UserRepository userRepository;
private final EmailService emailService;
// 构造器注入 - Spring 4.3+ 单构造器可不加 @Autowired
@Autowired
public UserService(UserRepository userRepository,
EmailService emailService) {
this.userRepository = userRepository;
this.emailService = emailService;
}
}
优点:
- 保证依赖不可变(final字段)
- 防止空指针(必须提供依赖)
- 对单元测试友好
- 支持循环依赖检测
2.3.2 Setter 注入
java
@Component
public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
2.3.3 字段注入(不推荐)
java
@Component
public class UserService {
@Autowired
private UserRepository userRepository; // 字段注入
}
为什么字段注入不推荐?
- 隐藏了外部依赖,不利于理解类的职责
- 无法使用 final 修饰
- 单元测试困难,需要反射注入
- 可能导致 NullPointerException
2.3.4 方法注入
java
// Lookup 方法注入 - 解决单例依赖原型的问题
@Component
@Scope("singleton")
public abstract class SingletonBean {
@Lookup
public abstract PrototypeBean getPrototypeBean();
public void process() {
PrototypeBean pb = getPrototypeBean(); // 每次获取新的实例
}
}
2.4 @Autowired 详细机制
java
// 1. 按类型装配(默认)
@Autowired
private UserDao userDao;
// 2. 配合 @Qualifier 按名称
@Autowired
@Qualifier("userDaoImpl1")
private UserDao userDao;
// 3. required 属性
@Autowired(required = false) // 找不到bean也不报错
private Optional<Service> service;
// 4. 注入集合
@Autowired
private List<UserDao> userDaoList; // 注入所有实现
@Autowired
private Map<String, UserDao> userDaoMap; // beanName -> bean
// 5. @Primary 指定首选
@Component
@Primary
public class PrimaryUserDao implements UserDao { }
2.5 @Resource vs @Autowired
| 特性 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring | JSR-250 (JDK标准) |
| 默认装配方式 | byType | byName |
| 属性 | required | name, type |
| 可标记位置 | 构造器, 字段, 方法, 参数 | 字段, setter |
3. Bean 的配置与管理
3.1 Bean 作用域 (Scope)
3.1.1 Singleton(默认)
java
@Component
@Scope("singleton")
// 或 @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class SingletonBean {
// 整个容器中只有一个实例
// Spring默认使用单例注册表实现
}
实现原理: Spring 使用 ConcurrentHashMap 缓存单例 bean,key 为 beanName。
3.1.2 Prototype
java
@Component
@Scope("prototype")
// 或 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PrototypeBean {
// 每次请求创建新实例
// 注意: Spring不管理prototype bean的完整生命周期
}
3.1.3 Web 作用域
java
// Request 作用域 - 每个HTTP请求一个实例
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestBean { }
// Session 作用域 - 每个HTTP会话一个实例
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public class SessionBean { }
// Application 作用域 - 整个ServletContext一个实例
@Component
@Scope("application")
public class ApplicationBean { }
// WebSocket 作用域
@Component
@Scope("websocket")
public class WebSocketBean { }
3.2 Bean 生命周期详解
java
@Component
public class LifecycleBean implements
InitializingBean, // afterPropertiesSet()
DisposableBean, // destroy()
BeanNameAware, // setBeanName()
BeanFactoryAware, // setBeanFactory()
ApplicationContextAware { // setApplicationContext()
private String name;
public LifecycleBean() {
System.out.println("1. 实例化 - 构造方法");
}
@Autowired
public void setDependency(UserService service) {
System.out.println("2. 属性注入");
}
@Override
public void setBeanName(String name) {
this.name = name;
System.out.println("3. BeanNameAware - " + name);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
System.out.println("4. BeanFactoryAware");
}
@Override
public void setApplicationContext(ApplicationContext ctx) {
System.out.println("5. ApplicationContextAware");
}
@PostConstruct // JSR-250
public void postConstruct() {
System.out.println("6. @PostConstruct(优先于afterPropertiesSet)");
}
@Override
public void afterPropertiesSet() {
System.out.println("7. afterPropertiesSet");
}
// 自定义 init-method / Xml 配置
public void customInit() {
System.out.println("8. 自定义 init-method");
}
// Bean 就绪...
@PreDestroy
public void preDestroy() {
System.out.println("9. @PreDestroy");
}
@Override
public void destroy() {
System.out.println("10. DisposableBean.destroy()");
}
public void customDestroy() {
System.out.println("11. 自定义 destroy-method");
}
}
完整生命周期阶段:
css
[实例化] → [属性填充] → [Aware接口] → [BeanPostProcessor前置处理]
→ [初始化回调] → [BeanPostProcessor后置处理] → [就绪] → [销毁]
3.3 BeanPostProcessor
java
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
// 初始化之前调用
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof CustomBean) {
System.out.println("前置处理:" + beanName);
}
return bean; // 可以返回代理对象
}
// 初始化之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof CustomBean) {
System.out.println("后置处理:" + beanName);
}
return bean; // AOP生成代理的关键位置
}
}
3.4 Bean 配置方式
3.4.1 XML 配置
xml
<beans>
<!-- 构造器注入 -->
<bean id="userDao" class="com.example.UserDao"/>
<bean id="userService" class="com.example.UserService">
<constructor-arg ref="userDao"/>
<constructor-arg value="admin"/>
</bean>
<!-- Setter 注入 -->
<bean id="emailService" class="com.example.EmailService">
<property name="smtpServer" value="smtp.example.com"/>
<property name="port" value="587"/>
</bean>
<!-- 集合注入 -->
<bean id="complexService" class="com.example.ComplexService">
<property name="configList">
<list>
<value>config1</value>
<value>config2</value>
</list>
</property>
<property name="configMap">
<map>
<entry key="key1" value-ref="beanRef1"/>
<entry key="key2" value="value2"/>
</map>
</property>
</bean>
</beans>
3.4.2 Java 注解配置
java
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
@Bean
@Scope("singleton")
@Lazy // 延迟初始化
public DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
ds.setUsername("root");
ds.setPassword("password");
return ds;
}
@Bean
public JdbcTemplate jdbcTemplate(@Qualifier("dataSource") DataSource ds) {
return new JdbcTemplate(ds);
}
}
3.5 循环依赖
java
// A依赖B,B依赖A - 循环依赖
@Component
public class A {
@Autowired
private B b;
}
@Component
public class B {
@Autowired
private A a;
}
Spring 解决循环依赖的三级缓存:
java
// 一级缓存:singletonObjects - 完全初始化完成的单例Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:earlySingletonObjects - 提前暴露的单例Bean(未完全初始化)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 三级缓存:singletonFactories - Bean的工厂对象
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
解决流程:
- 创建 A 实例 → 放入三级缓存
- 填充 A 的 b 属性 → 发现需要 B
- 创建 B 实例 → 放入三级缓存
- 填充 B 的 a 属性 → 从三级缓存获取 A 的早期引用
- B 完成初始化 → 放入一级缓存
- A 获取完整的 B → A 完成初始化
注意: 构造器注入无法解决循环依赖(因为无法获取早期引用),会抛出 BeanCurrentlyInCreationException。
4. AOP 面向切面编程
4.1 AOP 核心概念
scss
┌─────────────────────────────────────────┐
│ AOP 概念图解 │
├─────────────────────────────────────────┤
│ │
│ JoinPoint (连接点) │
│ └── 程序执行过程中的点(方法调用等) │
│ │
│ Pointcut (切入点) │
│ └── 匹配连接点的表达式 │
│ │
│ Advice (通知/增强) │
│ └── 在切入点上执行的操作 │
│ │
│ Aspect (切面) │
│ └── 切入点 + 通知的组合 │
│ │
│ Weaving (织入) │
│ └── 将切面应用到目标对象的过程 │
│ │
│ Target (目标对象) │
│ └── 被代理的对象 │
│ │
│ Introduction (引入) │
│ └── 动态添加方法/接口 │
│ │
└─────────────────────────────────────────┘
4.2 通知类型 (Advice)
java
@Aspect
@Component
public class LoggingAspect {
// 1. @Before - 前置通知
@Before("execution(* com.example.service.*.*(..))")
public void before(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("调用方法:" + methodName + ",参数:" + Arrays.toString(args));
}
// 2. @AfterReturning - 返回通知(成功返回后)
@AfterReturning(
pointcut = "execution(* com.example.service.*.*(..))",
returning = "result"
)
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("方法返回:" + result);
}
// 3. @AfterThrowing - 异常通知
@AfterThrowing(
pointcut = "execution(* com.example.service.*.*(..))",
throwing = "ex"
)
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
System.out.println("方法异常:" + ex.getMessage());
}
// 4. @After - 最终通知(类似finally)
@After("execution(* com.example.service.*.*(..))")
public void after(JoinPoint joinPoint) {
System.out.println("方法结束");
}
// 5. @Around - 环绕通知(最强大)
@Around("execution(* com.example.service.*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("环绕前:" + pjp.getSignature().getName());
Object result;
try {
result = pjp.proceed(); // 执行目标方法
} catch (Exception e) {
System.out.println("环绕异常:" + e.getMessage());
throw e;
}
long end = System.currentTimeMillis();
System.out.println("环绕后,耗时:" + (end - start) + "ms");
return result;
}
}
4.3 切入点表达式 (Pointcut)
java
@Aspect
@Component
public class PointcutExamples {
// 1. execution - 最常用
@Pointcut("execution(public * com.example.service.UserService.*(..))")
public void userServiceMethods() {}
// execution 语法分解:
// execution(
// [修饰符] 返回类型 [包.类.]方法名(参数列表) [throws 异常]
// )
// 通配符说明:
// * - 匹配任意字符(不包括包分隔符 .)
// .. - 匹配任意字符(包括包分隔符),匹配任意参数
// + - 匹配类及其所有子类
// 示例:
@Pointcut("execution(* com.example..*.*(..))") // com.example包及子包的所有方法
public void allMethodsInPackage() {}
@Pointcut("execution(* com.example.service.*.find*(..))") // service包下所有find开头的方法
public void finderMethods() {}
@Pointcut("execution(* com.example..*(..)) && within(com.example.service..*)")
public void combinedPointcut() {}
// 2. within - 限制类型匹配
@Pointcut("within(com.example.service.*)")
public void serviceLayer() {}
// 3. this - 代理对象类型匹配
@Pointcut("this(com.example.service.UserService)")
public void proxyIsUserService() {}
// 4. target - 目标对象类型匹配
@Pointcut("target(com.example.repository.BaseRepository)")
public void targetIsRepository() {}
// 5. args - 参数类型匹配
@Pointcut("args(Long, ..)")
public void firstArgIsLong() {}
// 6. @annotation - 方法注解匹配
@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
public void transactionalMethods() {}
// 7. @within - 类注解匹配
@Pointcut("@within(org.springframework.stereotype.Service)")
public void serviceClassMethods() {}
// 8. @args - 参数注解匹配
@Pointcut("@args(com.example.annotation.Validated)")
public void validatedArgs() {}
// 9. bean - Bean名称匹配
@Pointcut("bean(userService)") // 名称匹配
public void userServiceBean() {}
@Pointcut("bean(*Service)") // 通配符匹配
public void allServiceBeans() {}
}
4.4 AOP 实现原理
4.4.1 JDK 动态代理
java
// 基于接口的代理
public class JdkProxyDemo {
public static Object createProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
System.out.println("JDK代理 - 前置增强");
Object result = method.invoke(target, args);
System.out.println("JDK代理 - 后置增强");
return result;
}
);
}
}
4.4.2 CGLIB 代理
java
// 基于子类的代理
public class CglibProxyDemo {
public static Object createProxy(Class<?> targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
System.out.println("CGLIB代理 - 前置增强");
Object result = proxy.invokeSuper(obj, args);
System.out.println("CGLIB代理 - 后置增强");
return result;
});
return enhancer.create();
}
}
4.4.3 Spring 代理选择策略
java
// 默认策略
// 1. 如果目标实现了接口 → 使用JDK动态代理
// 2. 如果目标没有实现接口 → 使用CGLIB代理
// 3. Spring Boot 2.x 开始默认使用CGLIB代理(proxyTargetClass = true)
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB
public class AopConfig { }
JDK vs CGLIB 对比:
| 特性 | JDK 动态代理 | CGLIB |
|---|---|---|
| 代理方式 | 基于接口 | 基于继承 |
| 限制 | 目标必须实现接口 | 不能代理final类/方法 |
| 性能 | 创建快,执行稍慢 | 创建慢,执行快 |
| 包位置 | java.lang.reflect | org.springframework.cglib |
4.5 多切面执行顺序
java
@Aspect
@Component
@Order(1) // 优先级最高
public class FirstAspect {
@Around("execution(* com.example..*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Order 1 - Before");
Object result = pjp.proceed();
System.out.println("Order 1 - After");
return result;
}
}
@Aspect
@Component
@Order(2)
public class SecondAspect {
@Around("execution(* com.example..*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Order 2 - Before");
Object result = pjp.proceed();
System.out.println("Order 2 - After");
return result;
}
}
// 执行结果:
// Order 1 - Before
// Order 2 - Before
// 目标方法...
// Order 2 - After
// Order 1 - After
// (类似同心圆:Order小的在最外层)
5. Spring 事务管理
5.1 事务核心接口
java
// 1. PlatformTransactionManager - 事务管理器
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition);
void commit(TransactionStatus status);
void rollback(TransactionStatus status);
}
// 实现类:
// DataSourceTransactionManager - JDBC
// JpaTransactionManager - JPA
// HibernateTransactionManager - Hibernate
// JtaTransactionManager - 分布式事务
// 2. TransactionDefinition - 事务定义
public interface TransactionDefinition {
int getPropagationBehavior(); // 传播行为
int getIsolationLevel(); // 隔离级别
int getTimeout(); // 超时时间
boolean isReadOnly(); // 是否只读
String getName(); // 事务名称
}
// 3. TransactionStatus - 事务状态
public interface TransactionStatus {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
boolean isCompleted();
}
5.2 声明式事务(推荐)
java
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private InventoryService inventoryService;
// 基本用法
@Transactional
public void createOrder(Order order) {
orderRepository.save(order);
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
}
// 详细配置
@Transactional(
propagation = Propagation.REQUIRED, // 传播行为
isolation = Isolation.READ_COMMITTED, // 隔离级别
timeout = 30, // 超时秒数
readOnly = false, // 非只读
rollbackFor = Exception.class, // 触发回滚的异常
noRollbackFor = ValidationException.class // 不触发回滚的异常
)
public void createOrderDetailed(Order order) {
// 事务操作
}
}
5.3 事务传播行为
java
public enum Propagation {
// 1. REQUIRED (默认) - 有则加入,无则新建
@Transactional(propagation = Propagation.REQUIRED)
// 2. REQUIRES_NEW - 总是新建事务,挂起当前事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
// 3. SUPPORTS - 有则加入,无则非事务运行
@Transactional(propagation = Propagation.SUPPORTS)
// 4. NOT_SUPPORTED - 非事务运行,挂起当前事务
@Transactional(propagation = Propagation.NOT_SUPPORTED)
// 5. MANDATORY - 必须在事务中,否则抛异常
@Transactional(propagation = Propagation.MANDATORY)
// 6. NEVER - 不能在事务中,否则抛异常
@Transactional(propagation = Propagation.NEVER)
// 7. NESTED - 嵌套事务(需要JDBC Savepoint支持)
@Transactional(propagation = Propagation.NESTED)
}
传播行为对比表:
| 传播行为 | 当前无事务 | 当前有事务 | 备注 |
|---|---|---|---|
| REQUIRED | 新建 | 加入 | 默认,最常用 |
| REQUIRES_NEW | 新建 | 新建(挂起) | 独立事务 |
| SUPPORTS | 非事务 | 加入 | 灵活 |
| NOT_SUPPORTED | 非事务 | 挂起 | 不参与事务 |
| MANDATORY | 抛异常 | 加入 | 强制事务 |
| NEVER | 非事务 | 抛异常 | 不允许事务 |
| NESTED | 新建 | 嵌套 | 部分回滚 |
5.4 事务隔离级别
java
public enum Isolation {
// 1. DEFAULT - 使用数据库默认级别
DEFAULT(-1),
// 2. READ_UNCOMMITTED - 读未提交(最低级别)
// 问题:脏读、不可重复读、幻读
READ_UNCOMMITTED(1),
// 3. READ_COMMITTED - 读已提交
// 问题:不可重复读、幻读
READ_COMMITTED(2),
// 4. REPEATABLE_READ - 可重复读
// 问题:幻读(MySQL InnoDB 通过MVCC避免了幻读)
REPEATABLE_READ(4),
// 5. SERIALIZABLE - 串行化(最高级别)
// 问题:无,但性能最差
SERIALIZABLE(8)
}
5.5 事务失效场景
java
@Service
public class TransactionPitfalls {
// ❌ 场景1:非public方法
@Transactional
private void privateMethod() { } // 事务不生效
@Transactional
protected void protectedMethod() { } // 事务不生效
// ❌ 场景2:同类方法调用(自调用)
@Transactional
public void methodA() {
this.methodB(); // 事务不生效!因为绕过了代理
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 没有被代理拦截
}
// ✅ 解决方案:注入自己(Spring 4.3+)
@Autowired
private TransactionPitfalls self;
@Transactional
public void methodC() {
self.methodB(); // 通过代理调用,事务生效
}
// ✅ 或使用AopContext
public void methodD() {
((TransactionPitfalls) AopContext.currentProxy()).methodB();
}
// ❌ 场景3:异常被捕获
@Transactional
public void methodE() {
try {
// 数据库操作
throw new RuntimeException("error");
} catch (Exception e) {
log.error("异常被捕获,事务不会回滚");
}
}
// ✅ 正确做法:手动回滚
@Transactional
public void methodF() {
try {
// 数据库操作
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw e;
}
}
// ❌ 场景4:checked异常默认不回滚
@Transactional // 默认只回滚RuntimeException和Error
public void methodG() throws Exception {
throw new Exception("checked异常,默认不回滚");
}
// ✅ 指定rollbackFor
@Transactional(rollbackFor = Exception.class)
public void methodH() throws Exception {
throw new Exception("指定回滚checked异常");
}
}
6. Spring MVC
6.1 核心架构
scss
请求处理流程:
┌──────────────┐ ┌────────────────┐ ┌──────────────────┐
│ Dispatcher │ ──→ │ HandlerMapping │ ──→ │ Controller │
│ Servlet │ │ │ │ (Handler) │
│ (前端控制器)│ │ 返回处理器链 │ │ 执行业务逻辑 │
└──────┬───────┘ └────────────────┘ └────────┬─────────┘
│ │
│ ↓
│ ┌──────────────┐ ┌──────────────┐
│ │ ViewResolver │←── │ ModelAndView │
│ │ 解析视图 │ │ 返回视图模型 │
│ └──────┬───────┘ └──────────────┘
│ │
↓ ↓
┌──────────┐ ┌───────────┐
│ Response │←───────────│ View │
│ │ 渲染 │ 渲染视图 │
└──────────┘ └───────────┘
6.2 DispatcherServlet 详解
java
// 前端控制器 - Spring MVC 的核心
@WebServlet(urlPatterns = "/")
public class DispatcherServlet extends FrameworkServlet {
// 初始化过程
@Override
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); // 文件上传解析器
initLocaleResolver(context); // 国际化解析器
initThemeResolver(context); // 主题解析器
initHandlerMappings(context); // 处理器映射器
initHandlerAdapters(context); // 处理器适配器
initHandlerExceptionResolvers(context); // 异常解析器
initRequestToViewNameTranslator(context); // 视图名翻译器
initViewResolvers(context); // 视图解析器
initFlashMapManager(context); // FlashMap管理器
}
// 核心请求处理方法
@Override
protected void doDispatch(HttpServletRequest request,
HttpServletResponse response) throws Exception {
// 1. 获取处理器执行链
HandlerExecutionChain handler = getHandler(request);
// 2. 获取处理器适配器
HandlerAdapter adapter = getHandlerAdapter(handler.getHandler());
// 3. 执行拦截器前置方法
handler.applyPreHandle(request, response);
// 4. 实际执行处理器
ModelAndView mv = adapter.handle(request, response, handler.getHandler());
// 5. 视图解析和渲染
processDispatchResult(request, response, handler, mv);
// 6. 执行拦截器后置方法
handler.applyPostHandle(request, response, mv);
}
}
6.3 Controller 编写
java
@RestController // = @Controller + @ResponseBody
@RequestMapping("/api/users")
@Validated
public class UserController {
@Autowired
private UserService userService;
// GET 请求 - 获取资源
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return ResponseEntity.ok(user);
}
// POST 请求 - 创建资源
@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody UserDTO dto) {
User user = userService.create(dto);
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(user.getId())
.toUri();
return ResponseEntity.created(location).body(user);
}
// PUT 请求 - 更新资源
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(
@PathVariable Long id,
@Valid @RequestBody UserDTO dto) {
User user = userService.update(id, dto);
return ResponseEntity.ok(user);
}
// DELETE 请求 - 删除资源
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
// PATCH 请求 - 部分更新
@PatchMapping("/{id}")
public ResponseEntity<User> patchUser(
@PathVariable Long id,
@RequestBody Map<String, Object> updates) {
User user = userService.patch(id, updates);
return ResponseEntity.ok(user);
}
// 请求参数
@GetMapping
public ResponseEntity<Page<User>> listUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(required = false) String name,
@RequestParam(required = false) String sort) {
// ...
}
// 矩阵变量 (需手动配置启用)
@GetMapping("/{id}/orders/{orderId}")
public ResponseEntity<Order> getOrder(
@PathVariable Long id,
@MatrixVariable(pathVar = "orderId") String q) {
// ...
}
}
6.4 拦截器 (Interceptor)
java
@Component
public class AuthInterceptor implements HandlerInterceptor {
// 前置处理 - Controller执行