Java进阶全套教程(三)------ Spring框架核心精讲
一、课程导学:Spring核心价值与企业定位
Spring框架是目前Java企业级开发的底层核心基石,市面上99%的Java后端项目(SpringBoot、SpringCloud微服务、分布式架构、ORM持久层框架整合)均基于Spring原生内核构建。相较于传统Java EE开发存在的代码高度耦合、对象资源浪费、事务管控混乱、通用功能重复开发、后期维护成本极高的痛点,Spring框架从底层架构层面彻底解决了企业开发的核心难题。
Spring核心设计理念主打解耦、简化、优雅、可拓展,以IOC控制反转、AOP面向切面编程为两大核心内核,衍生出事务管理、数据持久化整合、Web开发、定时任务、事件驱动等全套企业级能力,同时完美兼容各类第三方框架与中间件,是Java后端开发者必须精通的底层核心技术。
本教程摒弃传统教程的概念堆砌、老旧案例、应试习题,聚焦Spring6全新特性、IOC/DI底层原理、AOP企业级实战、声明式事务、定时任务落地、全注解开发 核心内容,基于电商支付、订单履约、日志溯源、事务一致性真实业务场景重构全部案例,所有代码原创可直接商用,配套底层源码剖析、生产环境避坑指南、企业规范化配置,适配单体项目、分布式微服务项目的开发标准。
学习本章后,可彻底吃透Spring底层运行机制,解决开发中Bean重复创建、依赖注入失效、事务回滚异常、切面拦截冲突、定时任务阻塞等高频生产问题,为后续SpringBoot、SpringCloud、分布式事务等高阶技术学习筑牢底层根基。
官方权威地址 :Spring官方网站 https://spring.io/
二、Spring6版本核心升级特性(企业必知)
Spring6是Spring框架的跨越式里程碑版本,距离Spring5版本迭代周期超4年,是适配SpringBoot3.x、Jakarta EE新标准的核心底层升级,也是目前企业新项目的首选版本,核心升级点全部适配现代Java开发规范:
-
JDK版本硬性升级:最低适配JDK17及以上版本,全面拥抱Java新特性(记录类、密封类、Lambda优化、模块化),彻底淘汰JDK8老旧版本,大幅优化框架底层性能与内存模型。
-
命名空间全面迁移 :将传统
javax.*包下的Servlet、JPA、事务等API全部迁移至jakarta.*命名空间,适配最新Jakarta EE 9、Jakarta EE 10企业级规范。 -
AOT编译技术支持:新增AOT(Ahead Of Time)提前编译能力,替代传统JIT即时编译,大幅提升项目启动速度、降低运行时内存占用,是云原生、容器化部署的核心优化。
-
架构轻量化优化:移除大量过期废弃API、老旧兼容代码,框架内核更精简,同时强化原生响应式编程支持,适配高并发、异步业务场景。
Spring6的所有升级,核心目的是为SpringBoot3.0+、SpringCloud微服务新版本提供底层支撑,是现代云原生Java开发的基础核心。
三、Spring整体体系结构与模块详解
Spring框架采用模块化分层架构 ,将不同功能拆分为独立模块,开发者可根据项目需求按需引入、灵活整合,无需加载全部模块,最大程度精简项目依赖、提升运行效率。完整核心模块划分如下:
3.1 核心容器模块(Core Container)
Spring框架的基础必备模块,所有Spring功能都依赖该模块运行,是整个框架的基石,包含核心组件:Core核心工具类、Beans Bean工厂、Context应用上下文、Expression表达式解析器,负责Bean的创建、管理、依赖注入、生命周期管控。
3.2 数据访问与整合模块(Data Access/Integration)
专注数据持久化与第三方数据框架整合,包含JDBC模板、ORM整合、事务管理、JMS消息对接等能力,可无缝整合MyBatis、Hibernate、JPA等持久层框架,简化数据库操作与事务管控。
3.3 Web开发模块
提供Web项目开发全套能力,核心包含SpringMVC、WebSocket、异步请求处理等,适配传统Web项目与RESTful接口开发,是Java Web开发的核心支撑。
3.4 扩展功能模块
-
AOP模块:提供原生面向切面编程实现,支持日志、权限、事务等通用功能的无侵入增强。
-
Aspects模块:无缝整合AspectJ第三方AOP框架,提供更强大的切点表达式、注解式AOP能力,企业开发主流使用。
-
Instrumentation模块:提供类加载、字节码增强工具,适配服务器端特殊运行环境。
-
Messaging模块:集成基础消息投递能力,支持消息队列、事件通知等场景开发。
-
Test模块:整合JUnit、Mock等测试框架,提供Spring项目专属单元测试、集成测试能力。
四、IOC控制反转(Spring核心内核一)
4.1 IOC核心思想与解决的业务痛点
IOC(Inversion of Control,控制反转)是Spring最核心、最基础的设计思想,彻底颠覆了传统Java开发的对象创建与管理方式。
传统开发模式 :开发者主动通过new关键字创建对象、管理对象生命周期、维护对象依赖关系,控制权在开发者代码中。这种模式存在两大致命问题:
1.资源冗余浪费:每次调用业务方法都需要手动创建对象,频繁创建销毁对象会造成JVM内存资源浪费,项目并发量越高,资源损耗越严重。
- 代码高度耦合 :上层代码直接依赖下层实现类,若后续需要替换底层实现,必须修改上层源码,违反软件设计开闭原则,后期维护、迭代成本极高。
IOC核心思想 :将对象的创建、销毁、依赖管理、生命周期管控 全部交给Spring容器统一管理,开发者无需手动操作对象,仅需使用对象即可,对象控制权从代码反转到框架容器,这就是控制反转。
4.2 传统耦合代码实战演示(电商场景)
以电商订单业务为例,模拟传统高耦合代码的弊端,无需任何框架,纯原生Java实现订单查询业务:
java
// 订单数据层接口
public interface OrderDao {
// 根据订单号查询订单详情
Order getOrderInfo(String orderNo);
}
// 订单数据层默认实现类(MySQL数据源)
public class OrderDaoMysqlImpl implements OrderDao {
@Override
public Order getOrderInfo(String orderNo) {
// 模拟从MySQL数据库查询订单数据
Order order = new Order();
order.setOrderNo(orderNo);
order.setAmount(299.9);
order.setStatus("已支付");
order.setCreateTime(new Date());
return order;
}
}
// 订单业务层
public class OrderService {
// 主动new实现类,代码强耦合
private OrderDao orderDao = new OrderDaoMysqlImpl();
public Order queryOrder(String orderNo){
// 每次调用业务方法,依赖固定实现类
return orderDao.getOrderInfo(orderNo);
}
}
// 实体类
class Order {
private String orderNo;
private double amount;
private String status;
private Date createTime;
// 省略getter、setter、toString方法
}
上述代码问题:若后续业务需要切换为Redis缓存查询订单,新增OrderDaoRedisImpl实现类,必须修改OrderService源码,违背开闭原则,且每次调用业务方法都会依赖固定对象,无法统一管理。
4.3 手动模拟IOC容器(吃透底层原理)
为彻底理解IOC底层,我们手动实现一个简易Spring IOC容器,通过配置文件+集合容器实现对象统一管理,彻底解耦代码:
第一步:创建配置文件spring-bean.properties,定义需要容器管理的对象
properties
# key:bean唯一标识,value:类全限定名
orderDao=com.ecommerce.dao.impl.OrderDaoMysqlImpl
orderService=com.ecommerce.service.OrderService
第二步:自定义IOC容器工具类,加载配置文件、创建并存储对象
java
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
// 自定义简易IOC容器
public class CustomIocContainer {
// 容器:存储所有Bean对象,key=bean标识,value=实例对象
private static final Map<String,Object> BEAN_CONTAINER = new HashMap<>();
// 静态代码块:项目启动时加载配置文件,初始化所有Bean
static {
try {
// 读取配置文件
InputStream inputStream = CustomIocContainer.class.getClassLoader().getResourceAsStream("spring-bean.properties");
Properties properties = new Properties();
properties.load(inputStream);
// 遍历配置,批量创建对象存入容器
Enumeration<Object> keys = properties.keys();
while (keys.hasMoreElements()){
String beanKey = keys.nextElement().toString();
String classFullName = properties.getProperty(beanKey);
// 反射创建对象
Object beanObj = Class.forName(classFullName).getDeclaredConstructor().newInstance();
BEAN_CONTAINER.put(beanKey,beanObj);
}
} catch (Exception e) {
throw new RuntimeException("IOC容器初始化失败",e);
}
}
// 对外提供获取Bean对象的方法
public static Object getBean(String beanKey){
return BEAN_CONTAINER.get(beanKey);
}
}
第三步:改造业务层代码,从容器获取对象,彻底解耦
java
public class OrderService {
// 不再手动new对象,从IOC容器获取
private OrderDao orderDao = (OrderDao) CustomIocContainer.getBean("orderDao");
public Order queryOrder(String orderNo){
return orderDao.getOrderInfo(orderNo);
}
}
第四步:测试容器效果
java
public class IocTest {
public static void main(String[] args) {
// 多次获取对象,验证单例特性
OrderService service1 = (OrderService) CustomIocContainer.getBean("orderService");
OrderService service2 = (OrderService) CustomIocContainer.getBean("orderService");
System.out.println("对象哈希值1:"+service1.hashCode());
System.out.println("对象哈希值2:"+service2.hashCode());
// 执行业务
System.out.println(service1.queryOrder("ORD20260515001"));
}
}
核心效果:容器全局单例对象,节约内存资源;切换底层实现只需修改配置文件,无需改动Java源码,彻底解决耦合问题。
4.4 Spring原生IOC容器实现(XML配置方式)
Spring框架内置成熟的IOC容器,无需手动编写容器代码,通过XML配置即可快速实现Bean管理,适配Spring6开发规范。
第一步:搭建Maven项目,引入Spring6核心依赖
xml
<dependencies>
<!-- Spring6核心上下文依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.11</version>
</dependency>
<!-- 单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
第二步:创建Spring核心配置文件 spring-context.xml,配置Bean
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置DAO层Bean:交由Spring容器管理 -->
<bean id="orderDao" class="com.ecommerce.dao.impl.OrderDaoMysqlImpl"/>
<!-- 配置Service层Bean -->
<bean id="orderService" class="com.ecommerce.service.OrderService"/>
</beans>
第三步:Spring容器获取Bean测试
java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringIocTest {
public static void main(String[] args) {
// 1. 初始化Spring核心容器,加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
// 2. 从容器中获取Bean对象
OrderService orderService = (OrderService) context.getBean("orderService");
// 3. 执行业务方法
Order order = orderService.queryOrder("ORD20260515002");
System.out.println("订单信息:"+order);
// 验证单例特性
OrderService service2 = (OrderService) context.getBean("orderService");
System.out.println("是否为同一个对象:"+(orderService == service2));
}
}
4.5 Spring两大核心容器接口详解
Spring IOC容器基于两套核心接口实现,层级分明、功能递进,是企业开发必须掌握的底层架构:
4.5.1 BeanFactory(顶层根接口)
Spring容器的最顶层接口 ,是Bean管理的基础规范,仅提供Bean的基础获取、判断功能,采用延迟加载策略,仅在获取Bean时才创建对象,内存占用极低,适合资源受限的嵌入式项目。
4.5.2 ApplicationContext(子接口,企业主流)
BeanFactory的子接口,继承所有基础功能,同时拓展了国际化支持、资源文件加载、事件发布、容器初始化监听等企业级能力,项目启动时一次性加载所有单例Bean,响应速度更快,是开发首选容器。
三大常用实现类:
-
ClassPathXmlApplicationContext:读取项目类路径下的XML配置文件,日常开发最常用。
-
FileSystemXmlApplicationContext:读取本地磁盘绝对路径的配置文件,适合自定义配置文件路径的场景。
-
AnnotationConfigApplicationContext:纯注解开发专用容器,无需XML配置,SpringBoot底层核心容器。
4.6 Bean对象的四种创建方式(企业全覆盖)
Spring支持多种Bean创建方式,适配不同业务场景,覆盖原生类、第三方工具类、自定义工厂类等场景:
4.6.1 空参构造创建(默认方式)
Spring默认通过类的空参构造方法实例化Bean,若类无空参构造,容器启动直接报错,是最基础的创建方式。
4.6.2 有参构造创建
适用于对象初始化需要传入参数的场景,通过XML配置构造参数实现对象创建。
4.6.3 实例工厂方法创建
自定义工厂类,通过工厂实例方法创建Bean,适用于复杂对象、需要前置处理的对象创建场景。
java
// 自定义订单工厂类
public class OrderBeanFactory {
// 实例工厂方法:创建订单DAO对象
public OrderDao createOrderDao(){
// 可添加复杂初始化逻辑
return new OrderDaoMysqlImpl();
}
}
xml
<!-- 配置工厂Bean -->
<bean id="orderFactory" class="com.ecommerce.factory.OrderBeanFactory"/>
<!-- 通过工厂实例方法创建目标Bean -->
<bean id="orderDaoByFactory" factory-bean="orderFactory" factory-method="createOrderDao"/>
4.6.4 静态工厂方法创建
通过工厂静态方法创建Bean,无需实例化工厂类,配置更简洁,适合工具类对象创建。
4.7 Bean作用域与创建策略(生产避坑核心)
通过scope属性可配置Bean的创建策略,适配单例、多实例、Web上下文等场景,五大作用域详解:
-
singleton(默认单例) :整个容器全局仅创建一个Bean实例,容器启动时初始化(可通过
lazy-init="true"延迟到首次使用时创建),适用于无状态业务类(Service、Dao)。 -
prototype(多例):每次从容器获取Bean都会创建全新实例,适用于有状态、数据独立的对象。
-
request:Web环境专属,每次HTTP请求创建一个Bean,请求结束销毁。
-
session:Web环境专属,每个用户会话创建一个Bean,会话过期销毁。
-
global-session:集群环境专属,全局会话共享Bean实例。
4.8 Bean生命周期(底层核心原理)
Spring Bean拥有完整的生命周期,开发者可自定义初始化、销毁方法,实现对象创建后初始化资源、销毁前释放资源的业务需求,完整流程:实例化对象 → 依赖注入 → 初始化方法执行 → 对象使用 → 销毁方法执行。
实战配置自定义生命周期方法:
java
public class OrderDaoMysqlImpl implements OrderDao {
// 自定义初始化方法:创建对象后自动执行
public void init(){
System.out.println("订单DAO初始化完成,加载数据库配置");
}
// 自定义销毁方法:容器关闭时自动执行
public void destroy(){
System.out.println("订单DAO销毁,释放数据库连接资源");
}
@Override
public Order getOrderInfo(String orderNo) {
Order order = new Order();
order.setOrderNo(orderNo);
order.setAmount(299.9);
order.setStatus("已支付");
return order;
}
}
xml
<!-- 配置生命周期方法 -->
<bean id="orderDao" class="com.ecommerce.dao.impl.OrderDaoMysqlImpl"
init-method="init" destroy-method="destroy" scope="singleton"/>
五、DI依赖注入(IOC核心实现)
5.1 DI核心概念
DI(Dependency Injection,依赖注入)是IOC思想的具体落地实现 。IOC实现了对象的统一创建,而DI实现了对象之间依赖关系的自动赋值,简单来说:IOC管创建,DI管赋值。
Spring容器会自动识别Bean之间的依赖关系,自动将依赖对象注入目标Bean中,无需开发者手动赋值,彻底解耦对象依赖。
5.2 三大手动注入方式(企业规范)
5.2.1 Setter方法注入(主流推荐)
通过属性的setter方法完成依赖注入,灵活性高,支持动态修改依赖对象,是企业开发最常用的注入方式。
java
public class OrderService {
// 依赖DAO对象
private OrderDao orderDao;
// 必须提供setter方法
public void setOrderDao(OrderDao orderDao) {
this.orderDao = orderDao;
}
public Order queryOrder(String orderNo){
return orderDao.getOrderInfo(orderNo);
}
}
xml
<bean id="orderDao" class="com.ecommerce.dao.impl.OrderDaoMysqlImpl"/>
<bean id="orderService" class="com.ecommerce.service.OrderService">
<!-- setter注入:ref引用容器中已存在的Bean -->
<property name="orderDao" ref="orderDao"/>
</bean>
5.2.2 构造方法注入(Spring6官方推荐)
通过有参构造方法注入依赖,保证对象初始化时依赖必须存在,避免空指针异常,Spring6官方优先推荐。
5.2.3 普通值与集合注入
Spring支持注入基本数据类型、字符串、List、Set、Map、Properties等所有数据类型,适配复杂业务属性配置,以下为完整实战案例:
java
public class SystemConfig {
// 普通数据类型
private String projectName;
private int timeout;
// 集合类型
private List<String> allowIpList;
private Map<String,String> configMap;
// 省略getter/setter
}
xml
<bean id="systemConfig" class="com.ecommerce.config.SystemConfig">
<property name="projectName" value="电商订单系统"/>
<property name="timeout" value="3000"/>
<property name="allowIpList">
<list>
<value>127.0.0.1</value>
<value>192.168.1.100</value>
</list>
</property>
<property name="configMap">
<map>
<entry key="maxOrderNum" value="1000"/>
<entry key="payChannel" value="alipay"/>
</map>
</property>
</bean>
5.3 自动依赖注入(简化开发)
Spring支持全自动注入,无需手动配置property标签,通过autowire属性自动匹配依赖对象,分为三种模式:
-
byName:根据属性名匹配容器中同名Bean,自动注入。
-
byType:根据属性类型匹配容器中同类型Bean,自动注入,企业最常用。
-
constructor:通过构造方法自动匹配依赖对象注入。
六、Spring注解开发(纯注解企业主流方案)
Spring6主推纯注解开发,彻底摒弃繁琐的XML配置,通过注解快速实现Bean注册、依赖注入、配置加载,是现代项目开发的标准方案。
6.1 核心Bean注册注解(分层规范)
四大注解功能一致,均用于将类注册为Spring Bean,仅用于区分业务分层,提升代码可读性:
-
@Component:通用Bean注解,适用于无法分层的工具类。
-
@Repository:专属DAO/持久层类,标识数据访问层。
-
@Service:专属Service/业务层类,标识业务逻辑层。
-
@Controller:专属Controller/控制层类,标识Web接口层。
注解默认Bean名称为类名首字母小写,支持手动指定Bean名称。
6.2 依赖注入核心注解
6.2.1 @Autowired(类型自动注入)
默认根据类型 自动注入,无需setter方法,简化代码,是最常用的注入注解。若容器存在多个同类型Bean,可配合@Qualifier指定Bean名称精准注入。
java
@Service
public class OrderService {
// 自动根据类型注入
@Autowired
@Qualifier("orderDaoMysqlImpl")
private OrderDao orderDao;
public Order queryOrder(String orderNo){
return orderDao.getOrderInfo(orderNo);
}
}
6.2.2 @Value(普通值注入)
用于注入字符串、基本数据类型,支持直接赋值或读取外部配置文件参数,完美适配系统配置参数注入。
6.3 纯注解配置类(替代XML文件)
通过配置类注解,彻底消灭XML文件,实现全注解开发,核心注解组合:
-
@Configuration:标识当前类为Spring配置类,替代XML配置文件。
-
@ComponentScan:指定包扫描路径,自动扫描注册注解Bean。
-
@PropertySource:加载外部properties配置文件。
-
@Bean:将方法返回值注册为Spring Bean,适配第三方类、工具类注册。
-
@Import:导入其他配置类,实现配置拆分,优化代码结构。
完整纯注解配置类实战:
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@ComponentScan("com.ecommerce") // 包扫描
@PropertySource("classpath:system.properties") // 加载外部配置
public class SpringConfig {
// 注册第三方工具类Bean
@Bean
public RedisUtil redisUtil(){
return new RedisUtil();
}
}
七、Spring AOP核心精讲(企业无侵入增强)
7.1 AOP核心思想与落地价值
AOP(面向切面编程)是横向编程思想 ,核心价值:在不修改原有业务源码的前提下,对目标方法进行无侵入功能增强。弥补OOP面向对象纵向继承的短板,专门处理项目中通用、重复的横向业务逻辑。
企业核心落地场景:接口日志记录、权限校验、接口耗时统计、异常统一捕获、事务控制、操作溯源、接口限流,几乎所有通用增强功能都基于AOP实现。
7.2 AOP六大核心术语(通俗落地解读)
-
连接点(JoinPoint):项目中所有可被AOP拦截的方法(Spring中仅支持方法级拦截),如订单查询、支付、退款等业务方法。
-
切点(PointCut) :通过表达式筛选出的需要增强的目标方法集合,精准匹配需要拦截的业务方法。
-
通知(Advice):拦截目标方法后执行的增强逻辑,如日志打印、权限校验,是具体的增强代码。
-
切面(Aspect) :切点+通知的组合体,定义了"哪些方法、何时执行、执行什么增强"。
-
目标对象(Target):被增强的原始业务类对象。
-
织入(Weaving):Spring将切面增强逻辑植入目标方法、生成代理对象的过程。
7.3 AOP底层实现原理
Spring AOP底层基于动态代理机制自动适配,无需开发者手动实现代理逻辑:
-
JDK动态代理:目标类实现接口时默认使用,基于接口生成代理对象,仅拦截接口定义方法。
-
CGLIB动态代理:目标类无接口时自动使用,基于类继承生成子类代理,拦截所有公共方法。
7.4 五大通知类型(场景全覆盖)
Spring AOP提供五种通知类型,适配所有业务增强场景,执行时机与落地场景精准区分,基于注解实现企业级日志切面案例:
java
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect
@Component
public class LogAspect {
// 定义全局切点:拦截所有业务层方法
@Pointcut("execution(* com.ecommerce.service.*.*(..))")
public void servicePointCut(){}
// 前置通知:方法执行前执行(参数校验、权限校验)
@Before("servicePointCut()")
public void beforeAdvice(JoinPoint joinPoint){
System.out.println("【前置通知】方法开始执行:"+joinPoint.getSignature().getName());
System.out.println("【请求参数】:"+ Arrays.toString(joinPoint.getArgs()));
}
// 后置通知:方法正常执行完毕后执行(无异常)
@AfterReturning(value = "servicePointCut()",returning = "result")
public void afterReturningAdvice(Object result){
System.out.println("【后置通知】方法执行成功,返回结果:"+result);
}
// 异常通知:方法抛出异常时执行
@AfterThrowing(value = "servicePointCut()",throwing = "ex")
public void afterThrowingAdvice(Exception ex){
System.out.println("【异常通知】方法执行异常:"+ex.getMessage());
}
// 最终通知:无论是否异常,最终都会执行
@After("servicePointCut()")
public void afterAdvice(){
System.out.println("【最终通知】方法执行结束,完成资源释放");
}
// 环绕通知:方法前后均可增强,可控制方法执行
@Around("servicePointCut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
long startTime = System.currentTimeMillis();
// 执行目标方法
Object result = pjp.proceed();
long endTime = System.currentTimeMillis();
System.out.println("【环绕通知】方法执行耗时:"+(endTime-startTime)+"ms");
return result;
}
}
7.5 切点表达式实战(企业通用规范)
AspectJ切点表达式是AOP精准拦截的核心,标准语法:修饰符 返回值类型 包名.类名.方法名(参数列表),支持通配符匹配:
-
*****:匹配任意返回值、任意类名、任意方法名、单个任意参数。
-
...:匹配任意层级包、任意个数任意类型参数。
企业常用通用切点:execution(* com.ecommerce..*.*(..))(拦截电商项目所有包下所有方法)
八、Spring事务管控(生产核心)
8.1 事务核心概念
事务是一组不可分割的原子操作,核心特性:要么全部执行成功,要么全部执行失败回滚,杜绝部分成功、部分失败的数据不一致问题。企业开发中,事务统一配置在Service业务层,保障数据库操作的原子性。
8.2 Spring事务管理方案
Spring提供两种事务管理方案,企业开发100%使用声明式事务:
-
编程式事务:手动编写代码控制事务提交、回滚,代码侵入性强,极少使用。
-
声明式事务:基于AOP实现,无需修改业务代码,通过注解/配置声明事务规则,无侵入、高灵活,企业主流方案。
8.3 事务管理器核心适配
Spring针对不同持久层框架提供专属事务管理器,使用MyBatis、JDBC开发时,核心使用DataSourceTransactionManager事务管理器,适配所有关系型数据库事务管控。
8.4 注解式事务实战(@Transactional)
通过@Transactional注解快速开启事务,作用于类上时,所有公共方法都生效;作用于方法上时,仅当前方法生效,适配电商转账、订单创建等核心场景:
java
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
@Service
public class PayService {
// 开启事务:方法内所有数据库操作原子执行
@Transactional(rollbackFor = Exception.class)
public void transferMoney(String outUserId,String inUserId,double money){
// 1. 扣款
userAccountDao.reduceBalance(outUserId,money);
// 模拟业务异常
int num = 1/0;
// 2. 加款
userAccountDao.addBalance(inUserId,money);
}
}
8.5 事务核心配置参数(生产避坑)
-
rollbackFor :指定触发事务回滚的异常类型,默认仅回滚运行时异常,建议全局配置
Exception。 -
readOnly:开启只读事务,查询方法开启,提升数据库查询性能。
-
timeout:设置事务超时时间,超时自动回滚,避免事务卡死。
-
propagation:事务传播行为,解决多事务方法嵌套调用问题,默认REQUIRED。
-
isolation:事务隔离级别,解决并发事务脏读、不可重复读、幻读问题。
九、Spring Task定时任务(企业落地)
9.1 定时任务应用场景
定时任务是企业项目必备能力,适用于订单超时关闭、每日数据统计、定时清理日志、会员权益发放、定时同步数据等场景。Spring Task是Spring原生轻量级定时框架,无需引入第三方依赖,配置简单、性能稳定,替代传统Timer、Quartz。
9.2 注解式定时任务实战
基于纯注解实现定时任务,Spring6中只需开启定时任务注解驱动,配合@Scheduled即可快速实现:
第一步:配置类开启定时任务支持
java
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@ComponentScan("com.ecommerce")
@EnableScheduling // 开启定时任务注解驱动
public class TaskConfig {
}
第二步:编写定时任务业务类
java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class OrderTask {
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Cron表达式:每分钟执行一次,清理超时未支付订单
@Scheduled(cron = "0 * * * * *")
public void clearOverTimeOrder(){
System.out.println(SDF.format(new Date())+" 执行超时订单清理任务");
// 业务逻辑:查询超时未支付订单、关闭订单、释放库存
}
// 每天凌晨2点执行数据统计
@Scheduled(cron = "0 0 2 * * ?")
public void statisticsDailyData(){
System.out.println("执行每日订单数据统计任务");
}
}
9.3 Cron表达式核心语法与实战案例
Cron表达式是定时任务的核心,6位常用语法:秒 分 时 日 月 周,企业高频实战表达式:
-
0 0/5 * * * *:每5分钟执行一次 -
0 30 8 * * ?:每日早上8点30分执行 -
0 0 2 ? * 1-5:工作日凌晨2点执行 -
0 15 10 L * ?:每月最后一天10点15分执行
9.4 定时任务多线程优化(生产必备)
Spring Task默认单线程执行,多任务场景会出现任务阻塞、执行延迟问题,通过自定义线程池实现多线程并行执行任务:
java
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Component;
import java.util.concurrent.Executors;
@Configuration
@EnableScheduling
public class TaskConfig implements SchedulingConfigurer {
// 自定义定时任务线程池,支持多任务并行执行
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// 创建固定大小线程池,避免单线程阻塞
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
}
}
十、Spring6 整合 MyBatis 企业完整实战(核心必学)
MyBatis是Java生态最主流的轻量级持久层框架 ,用于替代原生JDBC,简化数据库CRUD操作、灵活编写SQL、实现结果集自动封装。Spring原生无持久层能力,实际项目中必须Spring + MyBatis整合使用,结合Spring IOC容器管理MyBatis核心对象、事务统一管控,是企业项目标准开发架构。
本章基于Spring6 + MyBatis3.5.13 + MySQL8 最新稳定版本,讲解两套整合方案:纯注解零配置(SpringBoot底层方案) 、XML配置方案(传统项目兼容),完整实现数据库CRUD、事务控制、分页查询、单元测试,覆盖生产所有落地场景。
10.1 整合核心原理与依赖说明
10.1.1 整合核心依赖
Spring与MyBatis无法直接整合,依赖官方适配包mybatis-spring,该框架专门适配Spring容器,可将MyBatis核心组件(SqlSession、Mapper、数据源)交由Spring IOC统一管理,彻底解决原生MyBatis手动创建会话、资源频繁开闭的问题。
10.1.2 核心整合组件
-
DataSource(数据源):数据库连接池,统一管理数据库连接,替代原生DriverManager,提升性能。
-
SqlSessionFactoryBean:MyBatis核心工厂Bean,Spring整合MyBatis的核心,用于创建SqlSession会话。
-
MapperScannerConfigurer:Mapper接口扫描器,自动扫描DAO接口,批量生成代理对象注入Spring容器。
-
DataSourceTransactionManager:Spring事务管理器,接管MyBatis数据库事务,实现声明式事务管控。
10.2 项目环境搭建与Maven依赖
搭建标准Maven Java项目,适配Spring6最新规范,导入全套整合依赖(包含Spring核心、JDBC、MyBatis适配、数据库驱动、测试依赖)。
xml
<properties>
<spring.version>6.0.11</spring.version>
<mybatis.version>3.5.13</mybatis.version>
<mybatis-spring.version>3.0.3</mybatis-spring.version>
<junit.version>4.13.2</junit.version>
</properties>
<dependencies>
<!-- Spring6核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring JDBC+事务核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- MyBatis核心依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- Spring整合MyBatis适配包(核心必备) -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- MySQL8数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
<scope>runtime</scope>
</dependency>
<!-- 单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- Spring测试整合依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
10.3 数据库准备(实战数据表)
创建测试数据库与用户表,用于后续CRUD实战,适配MySQL8语法:
sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS spring_mybatis DEFAULT CHARACTER SET utf8mb4;
USE spring_mybatis;
-- 创建用户测试表
CREATE TABLE `user` (
`id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`username` VARCHAR(30) NOT NULL COMMENT '用户名',
`password` VARCHAR(30) NOT NULL COMMENT '密码',
`age` INT DEFAULT 0 COMMENT '年龄',
`create_time` DATETIME DEFAULT NOW() COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 初始化测试数据
INSERT INTO `user`(username,password,age) VALUES ('张三','123456',22),('李四','654321',25);
10.4 纯注解整合方案(Spring6企业主流)
彻底摒弃XML配置,通过Java配置类+注解完成所有整合配置,是Spring6、SpringBoot项目标准方案,简洁高效、便于维护。
10.4.1 编写数据库配置文件
在resources目录创建jdbc.properties,统一管理数据库参数,避免硬编码:
properties
# MySQL8数据库配置
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_mybatis?useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true
jdbc.username=root
jdbc.password=root
10.4.2 核心整合配置类(完整版)
编写Spring全局配置类,整合数据源、MyBatis工厂、Mapper扫描、事务管理器,一键完成所有配置:
java
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
// 全局配置类
@Configuration
// 包扫描:扫描业务层、持久层注解
@ComponentScan("com.ecommerce")
// 加载数据库配置文件
@PropertySource("classpath:jdbc.properties")
// 开启事务注解驱动
@EnableTransactionManagement
// 扫描Mapper接口,自动创建代理Bean注入容器
@MapperScan("com.ecommerce.mapper")
public class MyBatisSpringConfig {
// 注入配置文件环境变量
private final Environment env;
public MyBatisSpringConfig(Environment env) {
this.env = env;
}
// 1. 配置数据源DataSource
@Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driver"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
// 2. 配置MyBatis核心工厂:SqlSessionFactory
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
// 绑定数据源
factoryBean.setDataSource(dataSource);
// 设置实体类别名包(简化映射配置)
factoryBean.setTypeAliasesPackage("com.ecommerce.entity");
// 加载Mapper映射文件
Resource[] resources = new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/*.xml");
factoryBean.setMapperLocations(resources);
return factoryBean;
}
}
10.5 业务代码分层实战(CRUD完整实现)
遵循企业三层架构:Entity实体层 → Mapper持久层 → Service业务层,完整实现增删改查功能。
10.5.1 实体类Entity
创建用户实体类,对应数据库user表,适配驼峰命名:
java
package com.ecommerce.entity;
import java.util.Date;
// 用户实体类
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private Date createTime;
// 无参、有参构造
public User(){}
public User(String username, String password, Integer age) {
this.username = username;
this.password = password;
this.age = age;
}
// 省略getter、setter、toString方法
}
10.5.2 Mapper持久层接口
创建Mapper接口,定义数据库CRUD方法,无需手动实现,由MyBatis动态代理生成:
java
package com.ecommerce.mapper;
import com.ecommerce.entity.User;
import java.util.List;
public interface UserMapper {
// 新增用户
int insertUser(User user);
// 根据ID删除用户
int deleteUserById(Integer id);
// 修改用户信息
int updateUser(User user);
// 根据ID查询用户
User getUserById(Integer id);
// 查询所有用户
List<User> listAllUser();
}
10.5.3 Mapper XML映射文件
在resources/mapper目录创建UserMapper.xml,编写SQL语句,实现方法与SQL绑定:
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 绑定对应Mapper接口全限定名 -->
<mapper namespace="com.ecommerce.mapper.UserMapper">
<!-- 新增用户 -->
<insert id="insertUser">
INSERT INTO user(username,password,age) VALUES(#{username},#{password},#{age})
</insert>
<!-- 删除用户 -->
<delete id="deleteUserById">
DELETE FROM user WHERE id = #{id}
</delete>
<!-- 修改用户 -->
<update id="updateUser">
UPDATE user SET username=#{username},age=#{age} WHERE id=#{id}
</update>
<!-- 根据ID查询 -->
<select id="getUserById" resultType="com.ecommerce.entity.User">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 查询全部 -->
<select id="listAllUser" resultType="com.ecommerce.entity.User">
SELECT * FROM user
</select>
</mapper>
10.5.4 Service业务层实现
创建业务接口与实现类,通过Spring自动注入Mapper对象,封装业务逻辑:
java
// 业务接口
package com.ecommerce.service;
import com.ecommerce.entity.User;
import java.util.List;
public interface UserService {
void addUser(User user);
void removeUser(Integer id);
void modifyUser(User user);
User getUser(Integer id);
List<User> listUser();
}
java
// 业务实现类
package com.ecommerce.service.impl;
import com.ecommerce.entity.User;
import com.ecommerce.mapper.UserMapper;
import com.ecommerce.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
// 自动注入Mapper代理对象
@Autowired
private UserMapper userMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void addUser(User user) {
userMapper.insertUser(user);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void removeUser(Integer id) {
userMapper.deleteUserById(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void modifyUser(User user) {
userMapper.updateUser(user);
}
@Override
@Transactional(readOnly = true)
public User getUser(Integer id) {
return userMapper.getUserById(id);
}
@Override
@Transactional(readOnly = true)
public List<User> listUser() {
return userMapper.listAllUser();
}
}
10.6 单元测试(Spring整合测试)
使用SpringTest框架编写测试类,加载Spring容器,测试完整CRUD功能,替代main方法测试:
java
package com.ecommerce.test;
import com.ecommerce.config.MyBatisSpringConfig;
import com.ecommerce.entity.User;
import com.ecommerce.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
// Spring整合JUnit测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyBatisSpringConfig.class)
public class SpringMyBatisTest {
@Autowired
private UserService userService;
// 测试新增用户
@Test
public void testAddUser(){
User user = new User("王五","123789",28);
userService.addUser(user);
System.out.println("用户新增成功");
}
// 测试查询所有用户
@Test
public void testListUser(){
List<User> userList = userService.listUser();
userList.forEach(System.out::println);
}
// 测试修改用户
@Test
public void testUpdateUser(){
User user = new User("王五","123789",30);
user.setId(3);
userService.modifyUser(user);
System.out.println("用户修改成功");
}
// 测试删除用户
@Test
public void testDeleteUser(){
userService.removeUser(3);
System.out.println("用户删除成功");
}
}
10.7 XML配置兼容方案(传统项目适配)
针对老旧传统项目,提供XML完整配置方案,功能与纯注解方案完全一致,可直接替换使用:
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"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 加载外部配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/><!-- 开启包扫描 -->
<context:component-scan base-package="com.ecommerce"/>
<!-- 1. 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 2. 配置MyBatis SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.ecommerce.entity"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!-- 3. 扫描Mapper接口,自动生成代理Bean -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ecommerce.mapper"/>
</bean>
<!-- 4. 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 5. 开启事务注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
10.8 整合事务实战与生产避坑
10.8.1 事务生效核心规则
Spring整合MyBatis事务基于AOP实现,必须满足以下条件才会生效:
-
注解位置 :
@Transactional注解必须加在public方法上,私有方法、静态方法事务失效。 -
异常回滚 :默认仅回滚运行时异常,必须配置
rollbackFor = Exception.class捕获所有异常。 -
调用方式:内部方法自调用(this.xxx())事务失效,必须通过Spring容器代理对象调用。
10.8.2 生产高频避坑点
-
Mapper文件找不到:确保XML映射文件路径、namespace与Mapper接口完全一致。
-
字段映射失效:数据库下划线字段与实体驼峰属性不匹配,可在MyBatis配置中开启驼峰自动转换。
-
事务不回滚:检查是否捕获异常未抛出、方法非public、内部自调用问题。
-
容器启动报错:Spring6必须适配mybatis-spring3.x版本,低版本会出现类加载异常。
10.9 章节总结
本章节完整实现了Spring6 + MyBatis企业级整合,核心掌握三点:
-
整合核心:通过
SqlSessionFactoryBean绑定数据源、@MapperScan扫描持久层接口,交由Spring容器统一管理MyBatis所有核心组件。 -
开发规范:严格遵循三层架构,Service层添加声明式事务,保障数据库操作原子性。
-
方案选型:新项目优先使用纯注解整合方案,简洁无冗余;老旧项目兼容XML配置方案,适配迭代需求。
该整合方案是SpringBoot、微服务项目数据持久层的底层基础,所有企业级数据库开发均基于此架构延伸拓展。