Java进阶全套教程(三)—— Spring框架核心精讲

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内存资源浪费,项目并发量越高,资源损耗越严重。

  1. 代码高度耦合 :上层代码直接依赖下层实现类,若后续需要替换底层实现,必须修改上层源码,违反软件设计开闭原则,后期维护、迭代成本极高。

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&gt;
    &lt;/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"&gt;

    <!-- 新增用户 -->
    <insert id="insertUser">
        INSERT INTO user(username,password,age) VALUES(#{username},#{password},#{age})
    &lt;/insert&gt;

    <!-- 删除用户 -->
    <delete id="deleteUserById">
        DELETE FROM user WHERE id = #{id}
    </delete&gt;

    <!-- 修改用户 -->
    <update id="updateUser">
        UPDATE user SET username=#{username},age=#{age} WHERE id=#{id}
    </update&gt;

    <!-- 根据ID查询 -->
    <select id="getUserById" resultType="com.ecommerce.entity.User">
        SELECT * FROM user WHERE id = #{id}
    &lt;/select&gt;

    <!-- 查询全部 -->
    <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"&gt;

    <!-- 加载外部配置文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/><!-- 开启包扫描 -->
    <context:component-scan base-package="com.ecommerce"/&gt;

    <!-- 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&gt;

    <!-- 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"/&gt;
    &lt;/bean&gt;

    <!-- 3. 扫描Mapper接口,自动生成代理Bean -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.ecommerce.mapper"/&gt;
    &lt;/bean&gt;

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

    <!-- 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企业级整合,核心掌握三点:

  1. 整合核心:通过SqlSessionFactoryBean绑定数据源、@MapperScan扫描持久层接口,交由Spring容器统一管理MyBatis所有核心组件。

  2. 开发规范:严格遵循三层架构,Service层添加声明式事务,保障数据库操作原子性。

  3. 方案选型:新项目优先使用纯注解整合方案,简洁无冗余;老旧项目兼容XML配置方案,适配迭代需求。

该整合方案是SpringBoot、微服务项目数据持久层的底层基础,所有企业级数据库开发均基于此架构延伸拓展。

相关推荐
阿里嘎多学长3 小时前
2026-05-22 GitHub 热点项目精选
开发语言·程序员·github·代码托管
始三角龙4 小时前
LeetCode hoot 100 -- 缺失的第一个正整数
算法·leetcode·职场和发展
彭于晏Yan4 小时前
OkHttp 与 RestTemplate 技术选型对比
java·spring boot·后端·okhttp
jzlhll1234 小时前
Kotlin 协程高级用法之 NonCancellable
android·开发语言·kotlin
金銀銅鐵4 小时前
[Java] 如何理解 class 文件中字段的 descriptor?
java·后端
500844 小时前
Graph Engine 是什么,为什么需要它
java·人工智能·性能优化·ocr·wpf
我是唐青枫4 小时前
C#.NET YARP + OpenTelemetry:网关链路追踪实战
开发语言·c#·.net
芯芯点灯4 小时前
gd32f303烧录提示Flash Timeout. Reset the Target and try it again.;
开发语言·前端·javascript