吃透 Spring 体系结构
在Java企业级开发领域,Spring框架无疑是当之无愧的基石。无论是微服务架构、分布式系统,还是传统的单体应用,Spring都以其强大的扩展性、灵活性和易用性,成为开发者的首选框架。但很多开发者在使用Spring时,往往停留在“API调用”层面,对其底层体系结构、核心设计思想一知半解,导致遇到复杂问题时难以定位,更无法充分发挥Spring的强大能力。
一、Spring体系结构整体概览
Spring并非单一框架,而是一个庞大的生态体系,核心围绕“简化Java开发”这一目标展开。其整体架构采用分层设计和模块化拆分,既保证了核心功能的简洁性,又通过扩展模块满足不同场景的需求。
1.1 核心架构图

1.2 架构核心设计思想
Spring的所有功能都构建在两大核心思想之上,这也是理解整个Spring体系的关键:
- 控制反转(IOC):将对象的创建、依赖管理等控制权从业务代码转移到Spring容器,实现“依赖注入”,降低代码耦合度。
- 面向切面编程(AOP):在不修改原有代码的前提下,通过动态代理为代码添加通用功能(如日志、事务、权限校验),实现关注点分离。
这两大思想贯穿于Spring的所有核心模块,是Spring生态的“灵魂”。后续所有模块的解析,都会围绕这两个核心展开。
二、核心容器模块:Spring的“心脏”
核心容器(Core Container)是Spring的基础,负责对象的创建、管理和依赖注入,是所有其他模块的支撑。包含Beans、Core、Context、Expression Language四个子模块。
2.1 Core模块:核心工具类
Core模块提供了Spring框架的基础工具类,是整个Spring的“工具包”,其他模块都依赖于它。核心功能包括:
- 资源访问(Resource接口,统一文件、URL、类路径等资源的访问方式)
- 类型转换(TypeConverter接口,实现不同类型之间的安全转换)
- 日志适配(整合JCL、SLF4J等日志框架,提供统一的日志接口)
实战示例:Resource资源访问
package com.jam.demo.core; import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.util.FileCopyUtils; import java.io.IOException; import java.nio.charset.StandardCharsets; /** * Spring Core模块资源访问示例 * @author ken */ @Slf4j public class ResourceDemo { public static void main(String[] args) { // 访问类路径下的配置文件 Resource resource = new ClassPathResource("application.properties"); try { // 使用Spring工具类读取文件内容 byte[] content = FileCopyUtils.copyToByteArray(resource.getInputStream()); String contentStr = new String(content, StandardCharsets.UTF_8); log.info("配置文件内容:\n{}", contentStr); } catch (IOException e) { log.error("读取配置文件失败", e); } } } 2.2 Beans模块:Bean的核心管理
Beans模块是IOC思想的核心实现,负责Bean的定义、创建、注册和管理。核心概念包括:
- BeanDefinition:描述Bean的元数据(类名、属性、依赖、作用域等)
- BeanFactory:Bean容器的顶层接口,提供Bean的获取、创建功能
- BeanWrapper:对Bean对象进行包装,提供属性设置、类型转换等功能
核心底层逻辑
- 开发者通过XML、注解(@Component、@Bean)等方式定义Bean;
- Spring解析这些定义,生成BeanDefinition对象;
- BeanFactory根据BeanDefinition创建Bean实例(默认单例,懒加载);
- 通过BeanWrapper为Bean设置属性和依赖。
实战示例:手动创建BeanFactory管理Bean
package com.jam.demo.beans; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; /** * BeanFactory手动管理Bean示例 * @author ken */ @Slf4j public class BeanFactoryDemo { public static void main(String[] args) { // 1. 创建BeanFactory实例(默认实现类) DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 2. 定义BeanDefinition(描述UserService) BeanDefinition userServiceDefinition = new RootBeanDefinition(UserService.class); // 3. 向BeanFactory注册Bean beanFactory.registerBeanDefinition("userService", userServiceDefinition); // 4. 从BeanFactory获取Bean(此时才创建Bean实例,懒加载) UserService userService = beanFactory.getBean("userService", UserService.class); userService.sayHello("Spring Beans"); // 5. 验证单例特性(多次获取为同一实例) UserService userService2 = beanFactory.getBean("userService", UserService.class); log.info("是否为同一实例:{}", userService == userService2); } /** * 测试Bean类 * @author ken */ @Data public static class UserService { public void sayHello(String name) { log.info("Hello, {}! 这是BeanFactory创建的Bean", name); } } } 2.3 Context模块:应用上下文
Context模块基于Core和Beans模块,提供了更强大的应用上下文管理功能,是BeanFactory的增强版。核心优势:
- 非懒加载:默认启动时创建所有单例Bean(BeanFactory默认懒加载)
- 支持国际化、资源访问、事件发布等高级功能
- 提供多种实现类,适配不同环境(ClassPathXmlApplicationContext、AnnotationConfigApplicationContext等)
核心接口关系

实战示例:AnnotationConfigApplicationContext使用(注解驱动)
package com.jam.demo.context; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 注解驱动的应用上下文示例 * @author ken */ @Slf4j public class AnnotationContextDemo { public static void main(String[] args) { // 1. 创建注解驱动的应用上下文,扫描指定包下的注解Bean AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // 2. 获取Bean(UserService被@Bean注解定义) UserService userService = context.getBean(UserService.class); userService.queryUser("1001"); // 3. 关闭上下文 context.close(); } /** * 应用配置类,用于定义Bean * @author ken */ @Configuration public static class AppConfig { /** * 定义UserService Bean * @return UserService实例 */ @Bean public UserService userService() { return new UserService(); } } /** * 用户服务类 * @author ken */ public static class UserService { public void queryUser(String userId) { log.info("查询用户信息,用户ID:{}", userId); } } } 2.4 Expression Language模块:Spring表达式语言
Spring EL(SpEL)是一种强大的表达式语言,支持在运行时查询和操作对象。核心功能包括:
- 访问对象属性和方法
- 执行算术运算、逻辑运算
- 读取配置文件、系统属性
- 集合操作、正则表达式匹配
实战示例:SpEL表达式使用
package com.jam.demo.el; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import java.util.ArrayList; import java.util.List; /** * Spring EL表达式示例 * @author ken */ @Slf4j public class Speldemo { public static void main(String[] args) { // 1. 创建SpEL解析器 ExpressionParser parser = new SpelExpressionParser(); // 2. 简单表达式:算术运算 Expression exp1 = parser.parseExpression("100 + 200 * 3"); Integer result1 = exp1.getValue(Integer.class); log.info("算术运算结果:{}", result1); // 3. 访问对象属性和方法 User user = new User("张三", 25); StandardEvaluationContext context = new StandardEvaluationContext(user); Expression exp2 = parser.parseExpression("name"); String userName = exp2.getValue(context, String.class); log.info("用户姓名:{}", userName); Expression exp3 = parser.parseExpression("getName().toUpperCase()"); String upperName = exp3.getValue(context, String.class); log.info("姓名大写:{}", upperName); // 4. 集合操作 List<String> list = new ArrayList<>(); list.add("Spring"); list.add("Spring Boot"); list.add("Spring Cloud"); context.setVariable("list", list); Expression exp4 = parser.parseExpression("#list.stream().filter(s -> s.startsWith('Spring ')).collect(toList())"); List<String> resultList = exp4.getValue(context, List.class); log.info("集合过滤结果:{}", resultList); } /** * 测试用户类 * @author ken */ @Data public static class User { private String name; private Integer age; public User(String name, Integer age) { this.name = name; this.age = age; } } } 三、AOP模块:面向切面编程的实现
AOP模块是Spring实现面向切面编程的核心,通过动态代理技术,在不修改原有代码的前提下,为程序添加通用功能(如日志、事务、权限)。核心依赖于Core和Beans模块。
3.1 AOP核心概念
- 切面(Aspect):封装通用功能的类(如日志切面、事务切面)
- 连接点(JoinPoint):程序执行过程中的特定点(如方法调用、属性赋值)
- 切入点(Pointcut):通过表达式筛选出的需要增强的连接点
- 通知(Advice):切面在连接点执行的具体操作(前置、后置、环绕、异常、最终通知)
- 目标对象(Target):被增强的对象
- 代理对象(Proxy):Spring为目标对象创建的代理对象,用于执行增强逻辑
3.2 底层实现原理
Spring AOP默认使用JDK动态代理(针对接口),如果目标对象没有实现接口,则使用CGLIB动态代理(通过继承目标类)。核心流程:
- 开发者定义切面(@Aspect)和切入点(@Pointcut);
- Spring解析切面配置,生成Advisor(包含切入点和通知);
- 容器创建目标对象时,根据Advisor判断是否需要增强;
- 若需要增强,通过动态代理创建代理对象;
- 调用目标方法时,先执行代理对象的增强逻辑,再执行目标方法。
AOP执行流程

3.3 实战示例:AOP日志增强(结合最新Spring AOP)
1. 依赖配置(pom.xml)
<!-- Spring AOP核心依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>6.1.5</version> </dependency> <!-- AspectJ支持(Spring AOP依赖AspectJ表达式) --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.21</version> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> <scope>provided</scope> </dependency> 2. 切面类定义
package com.jam.demo.aop; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.util.Arrays; /** * 日志切面类,用于增强服务层方法的日志输出 * @author ken */ @Aspect @Component @Slf4j public class LogAspect { /** * 切入点表达式:匹配com.jam.demo.service包下所有类的所有公共方法 */ @Pointcut("execution(public * com.jam.demo.service..*(..))") public void servicePointcut() {} /** * 前置通知:方法执行前执行 * @param joinPoint 连接点对象,包含方法信息、参数等 */ @Before("servicePointcut()") public void beforeAdvice(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); String className = joinPoint.getTarget().getClass().getSimpleName(); Object[] args = joinPoint.getArgs(); log.info("【前置通知】{}类的{}方法开始执行,参数:{}", className, methodName, Arrays.toString(args)); } /** * 后置通知:方法执行后执行(无论成功与否) * @param joinPoint 连接点对象 */ @After("servicePointcut()") public void afterAdvice(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); String className = joinPoint.getTarget().getClass().getSimpleName(); log.info("【后置通知】{}类的{}方法执行结束", className, methodName); } /** * 返回通知:方法成功执行后执行,可获取返回值 * @param joinPoint 连接点对象 * @param result 方法返回值 */ @AfterReturning(pointcut = "servicePointcut()", returning = "result") public void afterReturningAdvice(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); String className = joinPoint.getTarget().getClass().getSimpleName(); log.info("【返回通知】{}类的{}方法执行成功,返回值:{}", className, methodName, result); } /** * 异常通知:方法执行异常时执行 * @param joinPoint 连接点对象 * @param e 异常对象 */ @AfterThrowing(pointcut = "servicePointcut()", throwing = "e") public void afterThrowingAdvice(JoinPoint joinPoint, Exception e) { String methodName = joinPoint.getSignature().getName(); String className = joinPoint.getTarget().getClass().getSimpleName(); log.error("【异常通知】{}类的{}方法执行异常,异常信息:{}", className, methodName, e.getMessage(), e); } /** * 环绕通知:包围方法执行,可控制方法是否执行、执行时机 * @param proceedingJoinPoint 可执行的连接点对象 * @return 方法返回值 * @throws Throwable 方法执行异常 */ @Around("servicePointcut()") public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { String methodName = proceedingJoinPoint.getSignature().getName(); String className = proceedingJoinPoint.getTarget().getClass().getSimpleName(); long startTime = System.currentTimeMillis(); Object result = null; try { // 执行前置逻辑 log.info("【环绕通知-前置】{}类的{}方法开始计时", className, methodName); // 执行目标方法 result = proceedingJoinPoint.proceed(); // 执行返回后逻辑 log.info("【环绕通知-返回】{}类的{}方法计时结束", className, methodName); } catch (Exception e) { // 执行异常逻辑 log.error("【环绕通知-异常】{}类的{}方法执行异常", className, methodName, e); throw e; } finally { // 计算方法执行时间 long costTime = System.currentTimeMillis() - startTime; log.info("【环绕通知-最终】{}类的{}方法执行耗时:{}ms", className, methodName, costTime); } return result; } } 3. 服务类(被增强的目标对象)
package com.jam.demo.service; import com.jam.demo.entity.User; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; /** * 用户服务类,被AOP增强 * @author ken */ @Service @Slf4j public class UserService { /** * 根据用户ID查询用户 * @param userId 用户ID * @return User对象 */ public User queryUserById(String userId) { // 模拟参数校验 if (ObjectUtils.isEmpty(userId)) { throw new IllegalArgumentException("用户ID不能为空"); } // 模拟数据库查询 User user = new User(); user.setUserId(userId); user.setUserName("张三"); user.setAge(25); user.setPhone("13800138000"); return user; } /** * 新增用户 * @param user 用户对象 * @return 新增成功的用户ID */ public String addUser(User user) { // 模拟参数校验 if (ObjectUtils.isEmpty(user) || !org.springframework.util.StringUtils.hasText(user.getUserName())) { throw new IllegalArgumentException("用户名不能为空"); } // 模拟数据库新增 String userId = "user_" + System.currentTimeMillis(); user.setUserId(userId); log.info("用户新增成功,用户信息:{}", user); return userId; } } 4. 实体类
package com.jam.demo.entity; import lombok.Data; /** * 用户实体类 * @author ken */ @Data public class User { /** * 用户ID */ private String userId; /** * 用户名 */ private String userName; /** * 年龄 */ private Integer age; /** * 手机号 */ private String phone; } 5. 配置类(开启AOP自动代理)
package com.jam.demo.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; /** * 应用配置类,开启AOP自动代理并扫描组件 * @author ken */ @Configuration @ComponentScan(basePackages = "com.jam.demo") @EnableAspectJAutoProxy(proxyTargetClass = true) // proxyTargetClass=true:强制使用CGLIB代理 public class AopConfig { } 6. 测试类
package com.jam.demo.aop; import com.jam.demo.config.AopConfig; import com.jam.demo.entity.User; import com.jam.demo.service.UserService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * AOP测试类 * @author ken */ public class AopTest { public static void main(String[] args) { // 初始化Spring上下文 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class); // 获取UserService代理对象 UserService userService = context.getBean(UserService.class); // 测试正常方法调用 System.out.println("===== 测试查询用户 ====="); User user = userService.queryUserById("1001"); // 测试新增用户 System.out.println("\n===== 测试新增用户 ====="); User newUser = new User(); newUser.setUserName("李四"); newUser.setAge(30); newUser.setPhone("13900139000"); userService.addUser(newUser); // 测试异常情况 System.out.println("\n===== 测试参数异常 ====="); try { userService.queryUserById(null); } catch (Exception e) { // 异常已被切面捕获并日志输出 } // 关闭上下文 context.close(); } } 四、数据访问/集成模块:连接数据层
数据访问/集成模块提供了Spring对数据访问层的支持,简化了JDBC、ORM框架(MyBatis、Hibernate)、事务管理等操作。核心模块包括JDBC、ORM、Transactions等。
4.1 事务管理模块(Transactions)
Spring事务管理是该模块的核心功能,通过AOP实现声明式事务(注解@Transactional)或编程式事务,支持多种事务管理器(JDBC事务、JTA事务等)。
核心底层逻辑
- 事务管理器(PlatformTransactionManager):统一的事务管理接口,不同数据访问技术有不同实现(如DataSourceTransactionManager用于JDBC/MyBatis);
- 事务定义(TransactionDefinition):描述事务属性(隔离级别、传播行为、超时时间、是否只读);
- 事务状态(TransactionStatus):描述事务的当前状态(是否新建、是否已提交、是否回滚);
- 核心流程:通过AOP拦截标注@Transactional的方法,在方法执行前开启事务,执行成功后提交事务,执行异常时回滚事务。
实战示例:编程式事务(最新Spring 6.x)
1. 依赖配置(pom.xml)
<!-- Spring 事务核心依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>6.1.5</version> </dependency> <!-- Spring JDBC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>6.1.5</version> </dependency> <!-- MySQL驱动 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.3.0</version> </dependency> <!-- MyBatis-Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.5</version> </dependency> <!-- HikariCP连接池(Spring默认) --> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>5.1.0</version> </dependency> <!-- FastJSON2 --> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.45</version> </dependency> <!-- Google Guava 集合工具 --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>33.2.1-jre</version> </dependency> <!-- Swagger3 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> 2. 数据库表SQL(MySQL 8.0)
-- 用户表 CREATE TABLE `t_user` ( `user_id` varchar(64) NOT NULL COMMENT '用户ID', `user_name` varchar(32) NOT NULL COMMENT '用户名', `age` int DEFAULT NULL COMMENT '年龄', `phone` varchar(20) DEFAULT NULL COMMENT '手机号', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; -- 订单表 CREATE TABLE `t_order` ( `order_id` varchar(64) NOT NULL COMMENT '订单ID', `user_id` varchar(64) NOT NULL COMMENT '用户ID', `order_amount` decimal(10,2) NOT NULL COMMENT '订单金额', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`order_id`), KEY `idx_user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表'; 3. 实体类
package com.jam.demo.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; /** * 订单实体类 * @author ken */ @Data @TableName("t_order") public class Order { /** * 订单ID */ @TableId("order_id") private String orderId; /** * 用户ID */ @TableField("user_id") private String userId; /** * 订单金额 */ @TableField("order_amount") private BigDecimal orderAmount; /** * 创建时间 */ @TableField("create_time") private LocalDateTime createTime; } 4. Mapper接口(MyBatis-Plus)
package com.jam.demo.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.jam.demo.entity.Order; import com.jam.demo.entity.User; import org.springframework.stereotype.Repository; /** * 订单Mapper * @author ken */ @Repository public interface OrderMapper extends BaseMapper<Order> { } package com.jam.demo.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.jam.demo.entity.User; import org.springframework.stereotype.Repository; /** * 用户Mapper * @author ken */ @Repository public interface UserMapper extends BaseMapper<User> { } 5. 服务类(编程式事务)
package com.jam.demo.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.jam.demo.entity.Order; import com.jam.demo.entity.User; import com.jam.demo.mapper.OrderMapper; import com.jam.demo.mapper.UserMapper; import com.google.common.collect.Lists; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; import java.util.UUID; /** * 订单服务类(编程式事务) * @author ken */ @Service @Slf4j @RequiredArgsConstructor public class OrderService { private final OrderMapper orderMapper; private final UserMapper userMapper; private final PlatformTransactionManager transactionManager; /** * 创建订单(包含用户创建,编程式事务) * @param userName 用户名 * @param age 年龄 * @param phone 手机号 * @param orderAmount 订单金额 * @return 订单ID */ public String createOrderWithUser(String userName, Integer age, String phone, BigDecimal orderAmount) { // 1. 参数校验 if (!StringUtils.hasText(userName, "用户名不能为空")) { throw new IllegalArgumentException("用户名不能为空"); } if (ObjectUtils.isEmpty(orderAmount) || orderAmount.compareTo(BigDecimal.ZERO) <= 0) { throw new IllegalArgumentException("订单金额必须大于0"); } // 2. 定义事务属性:默认隔离级别、传播行为REQUIRED、非只读 DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT); transactionDefinition.setTimeout(30); // 超时时间30秒 // 3. 开启事务 TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition); try { // 3.1 创建用户 User user = new User(); String userId = "user_" + UUID.randomUUID().toString().replace("-", ""); user.setUserId(userId); user.setUserName(userName); user.setAge(age); user.setPhone(phone); int userInsertCount = userMapper.insert(user); log.info("创建用户,影响行数:{},用户ID:{}", userInsertCount, userId); // 模拟异常(测试事务回滚) // if (true) { // throw new RuntimeException("模拟创建订单异常"); // } // 3.2 创建订单 Order order = new Order(); String orderId = "order_" + UUID.randomUUID().toString().replace("-", ""); order.setOrderId(orderId); order.setUserId(userId); order.setOrderAmount(orderAmount); order.setCreateTime(LocalDateTime.now()); int orderInsertCount = orderMapper.insert(order); log.info("创建订单,影响行数:{},订单ID:{}", orderInsertCount, orderId); // 4. 提交事务 transactionManager.commit(transactionStatus); log.info("创建订单和用户成功,事务提交"); return orderId; } catch (Exception e) { // 5. 回滚事务 transactionManager.rollback(transactionStatus); log.error("创建订单和用户失败,事务回滚", e); throw new RuntimeException("创建订单失败:" + e.getMessage()); } } /** * 根据用户ID查询订单列表 * @param userId 用户ID * @return 订单列表 */ public List<Order> queryOrdersByUserId(String userId) { if (!StringUtils.hasText(userId, "用户ID不能为空")) { throw new IllegalArgumentException("用户ID不能为空"); } LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Order::getUserId, userId); List<Order> orderList = orderMapper.selectList(queryWrapper); if (CollectionUtils.isEmpty(orderList)) { log.info("用户ID:{} 暂无订单", userId); return Lists.newArrayList(); } return orderList; } } 6. 配置类(数据源、事务管理器、MyBatis-Plus)
package com.jam.demo.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import com.zaxxer.hikari.HikariDataSource; import javax.sql.DataSource; import java.util.Properties; /** * 数据访问层配置(数据源、事务管理器、MyBatis-Plus) * @author ken */ @Configuration @MapperScan(basePackages = "com.jam.demo.mapper") // 扫描Mapper接口 public class DataSourceConfig { /** * 配置HikariCP数据源(Spring 6.x默认) * @return 数据源 */ @Bean public DataSource dataSource() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_demo?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"); dataSource.setUsername("root"); dataSource.setPassword("root123456"); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); // 连接池配置 dataSource.setMaximumPoolSize(10); // 最大连接数 dataSource.setMinimumIdle(5); // 最小空闲连接数 dataSource.setIdleTimeout(300000); // 空闲连接超时时间(5分钟) dataSource.setConnectionTimeout(30000); // 连接超时时间(30秒) return dataSource; } /** * 配置事务管理器(JDBC事务) * @param dataSource 数据源 * @return 事务管理器 */ @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } /** * 配置MyBatis-Plus SqlSessionFactory * @param dataSource 数据源 * @return SqlSessionFactory * @throws Exception 异常 */ @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); // 配置MyBatis-Plus插件(分页插件) MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); sessionFactory.setPlugins(interceptor); // 配置MyBatis属性 Properties properties = new Properties(); properties.setProperty("mapUnderscoreToCamelCase", "true"); // 下划线转驼峰 properties.setProperty("logImpl", "SLF4J"); // 日志实现 sessionFactory.setConfigurationProperties(properties); return sessionFactory.getObject(); } } 7. 控制器(结合Swagger3)
package com.jam.demo.controller; import com.jam.demo.entity.Order; import com.jam.demo.service.OrderService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; import java.util.List; /** * 订单控制器 * @author ken */ @RestController @RequestMapping("/api/order") @Api(tags = "订单管理接口") @RequiredArgsConstructor @Slf4j public class OrderController { private final OrderService orderService; /** * 创建订单(包含用户创建) * @param userName 用户名 * @param age 年龄 * @param phone 手机号 * @param orderAmount 订单金额 * @return 订单ID */ @PostMapping("/create") @ApiOperation(value = "创建订单", notes = "创建订单并自动创建关联用户,包含编程式事务") public String createOrder( @ApiParam(value = "用户名", required = true) @RequestParam String userName, @ApiParam(value = "年龄") @RequestParam(required = false) Integer age, @ApiParam(value = "手机号") @RequestParam(required = false) String phone, @ApiParam(value = "订单金额", required = true) @RequestParam BigDecimal orderAmount ) { return orderService.createOrderWithUser(userName, age, phone, orderAmount); } /** * 根据用户ID查询订单列表 * @param userId 用户ID * @return 订单列表 */ @GetMapping("/list") @ApiOperation(value = "查询订单列表", notes = "根据用户ID查询关联的订单列表") public List<Order> queryOrderList( @ApiParam(value = "用户ID", required = true) @RequestParam String userId ) { return orderService.queryOrdersByUserId(userId); } } 8. 启动类
package com.jam.demo; import io.swagger.annotations.Api; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import springfox.documentation.oas.annotations.EnableOpenApi; /** * 应用启动类 * @author ken */ @SpringBootApplication @EnableOpenApi // 开启Swagger3 public class SpringDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringDemoApplication.class, args); System.out.println("Spring Demo应用启动成功!访问Swagger3文档:http://localhost:8080/swagger-ui/index.html"); } } 4.2 ORM模块:整合MyBatis-Plus
Spring的ORM模块提供了对主流ORM框架的整合支持,通过Spring的事务管理和资源管理,简化ORM框架的使用。上面的实战示例已结合MyBatis-Plus实现了ORM操作,核心优势:
- 统一的事务管理:MyBatis-Plus的操作自动纳入Spring事务;
- 资源统一管理:数据源由Spring统一配置和管理,避免重复配置;
- 简化依赖注入:Mapper接口由Spring自动扫描并注入到Service中。
五、Web模块:Spring的Web开发支持
Web模块提供了Spring对Web开发的全面支持,包含Web、WebMVC、WebFlux等子模块,分别对应传统的Servlet开发、MVC开发和响应式开发。
5.1 WebMVC模块:Spring MVC核心
Spring MVC是基于Servlet的MVC框架,实现了请求的接收、处理和响应的完整流程。核心组件包括:
- 前端控制器(DispatcherServlet):统一接收请求,分发到对应的处理器;
- 处理器映射器(HandlerMapping):根据请求路径查找对应的处理器(Controller方法);
- 处理器适配器(HandlerAdapter):调用处理器方法,执行业务逻辑;
- 视图解析器(ViewResolver):将处理器返回的结果解析为视图(JSP、JSON等);
- 拦截器(HandlerInterceptor):拦截请求,执行前置、后置处理(如登录校验)。
Spring MVC请求处理流程

实战示例:Spring MVC拦截器(登录校验)
1. 拦截器实现类
package com.jam.demo.interceptor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.util.StringUtils; /** * 登录校验拦截器 * @author ken */ @Slf4j public class LoginInterceptor implements HandlerInterceptor { /** * 前置处理:请求执行前拦截 * @param request 请求对象 * @param response 响应对象 * @param handler 处理器 * @return true:放行;false:拦截 * @throws Exception 异常 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 1. 获取请求路径 String requestURI = request.getRequestURI(); log.info("登录拦截器拦截请求:{}", requestURI); // 2. 放行登录接口 if (requestURI.contains("/api/login")) { log.info("登录接口,直接放行"); return true; } // 3. 校验登录状态(从Session获取用户信息) HttpSession session = request.getSession(); Object user = session.getAttribute("loginUser"); if (!StringUtils.isEmpty(user)) { log.info("用户已登录,放行请求"); return true; } // 4. 未登录,返回401未授权 log.info("用户未登录,拦截请求"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("{\"code\":401,\"msg\":\"未登录,请先登录\"}"); return false; } /** * 后置处理:处理器方法执行后,视图渲染前 * @param request 请求对象 * @param response 响应对象 * @param handler 处理器 * @param modelAndView 模型和视图 * @throws Exception 异常 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("登录拦截器后置处理"); } /** * 完成处理:视图渲染后,请求完成 * @param request 请求对象 * @param response 响应对象 * @param handler 处理器 * @param ex 异常对象 * @throws Exception 异常 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("登录拦截器完成处理"); } } 2. 拦截器配置类
package com.jam.demo.config; import com.jam.demo.interceptor.LoginInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * Web MVC配置类,注册拦截器 * @author ken */ @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { // 注册登录拦截器,拦截所有/api/**路径的请求 registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/api/**") .excludePathPatterns("/api/login"); // 放行登录接口 } } 3. 登录控制器
package com.jam.demo.controller; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.util.StringUtils; import javax.servlet.http.HttpSession; /** * 登录控制器 * @author ken */ @RestController @RequestMapping("/api") @Api(tags = "登录管理接口") @Slf4j public class LoginController { /** * 登录接口 * @param username 用户名 * @param password 密码 * @param session Session对象 * @return 登录结果 */ @PostMapping("/login") @ApiOperation(value = "用户登录", notes = "用户登录并将用户信息存入Session") public String login( @ApiParam(value = "用户名", required = true) @RequestParam String username, @ApiParam(value = "密码", required = true) @RequestParam String password, HttpSession session ) { // 简单校验(实际开发中需查询数据库) if (!StringUtils.hasText(username, "用户名不能为空") || !StringUtils.hasText(password, "密码不能为空")) { return "{\"code\":400,\"msg\":\"用户名或密码不能为空\"}"; } if ("admin".equals(username) && "admin123".equals(password)) { // 登录成功,存入Session session.setAttribute("loginUser", username); log.info("用户{}登录成功", username); return "{\"code\":200,\"msg\":\"登录成功\"}"; } log.info("用户{}登录失败,用户名或密码错误", username); return "{\"code\":401,\"msg\":\"用户名或密码错误\"}"; } } 六、易混淆技术点辨析
6.1 BeanFactory vs ApplicationContext
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 加载方式 | 懒加载(默认),获取Bean时才创建 | 非懒加载(默认),启动时创建单例Bean |
| 功能范围 | 核心Bean管理功能 | 包含BeanFactory所有功能,新增国际化、事件发布、资源访问等 |
| 适用场景 | 资源紧张的环境(如移动端) | 企业级应用(绝大多数场景) |
| 实现类 | DefaultListableBeanFactory | AnnotationConfigApplicationContext、ClassPathXmlApplicationContext等 |
6.2 JDK 动态代理 vs CGLIB 动态代理
| 特性 | JDK 动态代理 | CGLIB 动态代理 |
|---|---|---|
| 实现原理 | 基于接口,生成接口的代理类 | 基于继承,生成目标类的子类 |
| 目标对象要求 | 必须实现接口 | 无需实现接口(但不能是final类/方法) |
| 创建效率 | 较快(直接生成接口代理类字节码) | 较慢(需通过ASM框架修改字节码) |
| 执行效率 | 较慢(反射调用目标方法) | 较快(直接调用子类方法,无反射) |
| 内存占用 | 较少 | 较多(生成的子类字节码更复杂) |
| Spring 中的使用场景 | 目标对象实现接口时默认使用 | 目标对象无接口时自动使用;可通过proxyTargetClass=true强制使用 |
核心差异总结
- 底层依赖不同:JDK动态代理依赖JDK原生的
java.lang.reflect.Proxy和InvocationHandler,CGLIB依赖ASM字节码操作框架; - 适用场景不同:JDK动态代理仅支持接口实现类,CGLIB支持任意非final类;
- 性能特点不同:JDK动态代理创建快、执行慢,CGLIB创建慢、执行快(适合单例Bean的长期使用场景)。
实战示例:JDK 动态代理 vs CGLIB 动态代理对比
1. JDK 动态代理实现(基于接口)
package com.jam.demo.proxy; import lombok.extern.slf4j.Slf4j; import org.springframework.util.ObjectUtils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * JDK 动态代理示例(基于接口) * @author ken */ @Slf4j public class JdkProxyDemo { // 目标接口 public interface UserDao { /** * 保存用户 * @param userName 用户名 * @return 保存结果 */ boolean saveUser(String userName); } // 目标对象(实现接口) public static class UserDaoImpl implements UserDao { @Override public boolean saveUser(String userName) { if (!org.springframework.util.StringUtils.hasText(userName)) { log.error("用户名不能为空"); return false; } log.info("JDK动态代理-保存用户:{}", userName); return true; } } // JDK动态代理处理器 public static class JdkProxyHandler implements InvocationHandler { // 目标对象 private final Object target; public JdkProxyHandler(Object target) { this.target = target; } /** * 代理方法执行逻辑 * @param proxy 代理对象 * @param method 目标方法 * @param args 方法参数 * @return 方法返回值 * @throws Throwable 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前置增强:日志输出 log.info("【JDK代理-前置】执行方法:{},参数:{}", method.getName(), args); // 执行目标方法 Object result = method.invoke(target, args); // 后置增强:结果输出 log.info("【JDK代理-后置】方法执行完成,返回值:{}", result); return result; } } // 测试方法 public static void main(String[] args) { // 1. 创建目标对象 UserDao target = new UserDaoImpl(); // 2. 创建JDK动态代理对象 UserDao proxy = (UserDao) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new JdkProxyHandler(target) ); // 3. 调用代理方法 proxy.saveUser("张三"); // 验证代理对象类型 log.info("代理对象类型:{}", proxy.getClass().getName()); log.info("是否为目标对象实例:{}", proxy instanceof UserDaoImpl); } } 2. CGLIB 动态代理实现(基于继承)
package com.jam.demo.proxy; import lombok.extern.slf4j.Slf4j; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.springframework.util.StringUtils; import java.lang.reflect.Method; /** * CGLIB 动态代理示例(基于继承) * @author ken */ @Slf4j public class CglibProxyDemo { // 目标对象(无需实现接口) public static class OrderDao { /** * 创建订单 * @param orderId 订单ID * @return 创建结果 */ public boolean createOrder(String orderId) { if (!StringUtils.hasText(orderId)) { log.error("订单ID不能为空"); return false; } log.info("CGLIB动态代理-创建订单:{}", orderId); return true; } } // CGLIB方法拦截器 public static class CglibProxyInterceptor implements MethodInterceptor { /** * 拦截目标方法,执行增强逻辑 * @param obj 代理对象(目标类的子类) * @param method 目标方法 * @param args 方法参数 * @param proxy 方法代理对象(用于调用目标方法) * @return 方法返回值 * @throws Throwable 异常 */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 前置增强:日志输出 log.info("【CGLIB代理-前置】执行方法:{},参数:{}", method.getName(), args); // 执行目标方法(使用proxy.invokeSuper避免递归调用) Object result = proxy.invokeSuper(obj, args); // 后置增强:结果输出 log.info("【CGLIB代理-后置】方法执行完成,返回值:{}", result); return result; } } // 测试方法 public static void main(String[] args) { // 1. 创建CGLIB增强器 Enhancer enhancer = new Enhancer(); // 2. 设置父类(目标类) enhancer.setSuperclass(OrderDao.class); // 3. 设置方法拦截器 enhancer.setCallback(new CglibProxyInterceptor()); // 4. 创建代理对象(目标类的子类) OrderDao proxy = (OrderDao) enhancer.create(); // 5. 调用代理方法 proxy.createOrder("order_1001"); // 验证代理对象类型 log.info("代理对象类型:{}", proxy.getClass().getName()); log.info("是否为目标对象实例:{}", proxy instanceof OrderDao); } } 3. 依赖配置(pom.xml,CGLIB 依赖)
<!-- CGLIB 依赖(Spring AOP已包含,单独使用时需引入) --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> 6.3 声明式事务 vs 编程式事务
| 特性 | 声明式事务(@Transactional) | 编程式事务(PlatformTransactionManager) |
|---|---|---|
| 实现方式 | 基于AOP,注解驱动 | 手动编码调用事务API |
| 代码侵入性 | 低(仅需添加注解) | 高(业务代码中嵌入事务逻辑) |
| 灵活性 | 较低(依赖注解属性配置) | 较高(可灵活控制事务边界、异常处理) |
| 配置复杂度 | 低(注解+少量配置) | 高(需手动管理事务开启、提交、回滚) |
| 适用场景 | 简单事务场景(单方法、固定事务属性) | 复杂事务场景(多方法组合、动态事务属性) |
| 异常处理 | 默认仅回滚RuntimeException及其子类 | 可自定义回滚异常类型 |
核心差异总结
- 核心思想不同:声明式事务是“面向配置”,通过注解简化事务管理;编程式事务是“面向代码”,通过API精确控制事务流程;
- 代码侵入性不同:声明式事务几乎无侵入,符合“开闭原则”;编程式事务侵入业务代码,维护成本高;
- 适用场景不同:绝大多数简单业务用声明式事务;复杂业务(如多步骤事务控制、动态决定事务属性)用编程式事务。
实战示例:声明式事务快速实现
package com.jam.demo.transaction; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.jam.demo.entity.User; import com.jam.demo.mapper.UserMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; /** * 声明式事务示例 * @author ken */ @Service @Slf4j @RequiredArgsConstructor public class DeclarativeTransactionService { private final UserMapper userMapper; /** * 声明式事务:修改用户信息 * 事务属性:默认传播行为REQUIRED,默认回滚RuntimeException * @param userId 用户ID * @param newUserName 新用户名 */ @Transactional(rollbackFor = Exception.class) // 指定所有异常都回滚 public void updateUserName(String userId, String newUserName) { // 参数校验 if (!StringUtils.hasText(userId, "用户ID不能为空") || !StringUtils.hasText(newUserName, "新用户名不能为空")) { throw new IllegalArgumentException("用户ID或新用户名不能为空"); } // 1. 查询用户 LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(User::getUserId, userId); User user = userMapper.selectOne(queryWrapper); if (user == null) { throw new RuntimeException("用户不存在,用户ID:" + userId); } // 2. 修改用户名 user.setUserName(newUserName); userMapper.updateById(user); log.info("修改用户{}的用户名为:{}", userId, newUserName); // 模拟异常(测试事务回滚) // if (true) { // throw new RuntimeException("模拟修改用户信息异常"); // } } } 6.4 Spring AOP vs AspectJ
| 特性 | Spring AOP | AspectJ |
|---|---|---|
| 实现方式 | 动态代理(JDK/CGLIB),运行时增强 | 字节码织入,编译期/类加载期增强 |
| 增强时机 | 运行时(程序运行时动态生成代理对象) | 编译期(.java→.class时织入)/类加载期(.class加载到JVM时织入) |
| 功能范围 | 仅支持方法级别的增强 | 支持方法、字段、构造函数等多种增强点 |
| 代码侵入性 | 低(无需修改目标类代码) | 编译期织入无侵入,加载期织入需修改类加载器 |
| 性能 | 运行时增强有一定性能开销 | 编译期织入无运行时开销,性能更优 |
| 集成复杂度 | 低(Spring框架内置支持) | 高(需引入AspectJ编译器、配置织入) |
| 适用场景 | 绝大多数企业级应用的方法增强场景 | 需字段/构造函数增强、对性能要求极高的场景 |
核心差异总结
- 增强机制本质不同:Spring AOP是“运行时增强”,基于动态代理;AspectJ是“编译期/类加载期增强”,基于字节码织入;
- 功能完备性不同:AspectJ功能更强大,支持更多增强点;Spring AOP聚焦方法增强,满足大部分业务需求;
- 易用性不同:Spring AOP集成简单,无需额外编译工具;AspectJ需额外配置编译器(如ajc),使用成本高;
- 性能不同:AspectJ编译期织入无运行时开销,性能优于Spring AOP;Spring AOP运行时动态代理有轻微性能损耗,但可忽略不计。
七、Spring 体系结构核心总结
Spring 体系结构的核心是“分层设计+模块化拆分”,围绕“IOC容器”和“AOP”两大核心思想,构建了覆盖核心容器、数据访问、Web开发、测试等全链路的生态体系。
7.1 核心模块依赖关系
- 核心容器(Core Container)是基础,所有其他模块都依赖于它;
- AOP模块依赖核心容器,通过IOC容器管理切面和目标对象;
- 数据访问/集成模块依赖核心容器和AOP,通过AOP实现事务管理;
- Web模块依赖核心容器和AOP,通过IOC管理Controller、Service等Bean,通过AOP实现拦截器等功能;
- 测试模块依赖核心容器,提供对Spring Bean的测试支持。
7.2 核心设计思想落地
- IOC容器:将对象的创建、依赖管理交给Spring,实现“组件解耦”,核心载体是BeanFactory和ApplicationContext;
- AOP:通过“关注点分离”,将通用功能(日志、事务、权限)从业务代码中抽离,通过动态代理/字节码增强织入业务流程,实现“代码复用”。
7.3 实践选型建议
- 容器选择:优先使用ApplicationContext(AnnotationConfigApplicationContext/AnnotationConfigServletWebServerApplicationContext),注解驱动开发更高效;
- 代理选择:默认使用Spring AOP的动态代理,无需手动干预;若目标对象无接口且需增强final方法,可考虑AspectJ;
- 事务选择:简单业务用声明式事务(@Transactional),复杂业务用编程式事务;
- 数据访问:整合MyBatis-Plus简化ORM操作,使用HikariCP连接池提升性能;
- Web开发:Spring MVC用于传统Servlet开发,Spring WebFlux用于响应式开发(高并发场景)。
八、附录:实战项目依赖汇总(pom.xml完整配置)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.4</version> <!-- Spring Boot最新稳定版本,对应Spring 6.1.5 --> <relativePath/> </parent> <groupId>com.jam.demo</groupId> <artifactId>spring-system-demo</artifactId> <version>1.0.0</version> <name>spring-system-demo</name> <description>Spring体系结构实战演示项目</description> <properties> <java.version>17</java.version> <lombok.version>1.18.30</lombok.version> <mybatis-plus.version>3.5.5</mybatis-plus.version> <fastjson2.version>2.0.45</fastjson2.version> <guava.version>33.2.1-jre</guava.version> <swagger.version>3.0.0</swagger.version> <cglib.version>3.3.0</cglib.version> </properties> <dependencies> <!-- Spring Boot核心依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- Spring Web依赖(Spring MVC) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring AOP依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- Spring 事务依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <!-- MyBatis-Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!-- MySQL驱动 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- FastJSON2 --> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>${fastjson2.version}</version> </dependency> <!-- Google Guava --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>${guava.version}</version> </dependency> <!-- Swagger3 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>${swagger.version}</version> </dependency> <!-- CGLIB --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>${cglib.version}</version> </dependency> <!-- 测试依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!-- Spring Boot Maven插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> <!-- Java编译插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project> 总结
Spring 体系结构并非孤立的模块堆砌,而是以“IOC容器”为核心、以“AOP”为扩展手段,层层递进、相互支撑的完整生态。理解Spring体系结构,关键在于抓住“IOC解耦”和“AOP复用”两大核心思想,明确各模块的定位和依赖关系。