Skip to content

Spring 框架核心原理

深入理解 Spring 框架的核心机制:IOC、AOP、Bean 生命周期与事务管理

一、IOC 容器原理

1.1 什么是 IOC

IOC(Inversion of Control,控制反转) 是一种设计思想,将对象的创建和管理权交给 Spring 容器,实现解耦。

java
// 传统方式:对象自行创建依赖
public class UserService {
    private UserDao userDao = new UserDaoImpl(); // 紧耦合
}

// Spring IOC:依赖注入
public class UserService {
    @Autowired
    private UserDao userDao; // 松耦合,由 Spring 注入
}

1.2 IOC 容器核心组件

┌─────────────────────────────────────────┐
│            ApplicationContext           │
│  (BeanFactory 的子接口,提供更多功能)      │
├─────────────────────────────────────────┤
│              BeanFactory                │
│         (IoC 容器的核心接口)              │
├─────────────────────────────────────────┤
│  BeanDefinitionRegistry (注册 Bean 定义) │
│  BeanDefinitionReader (读取 Bean 定义)    │
└─────────────────────────────────────────┘

核心接口:

接口作用
BeanFactoryIOC 容器基础接口,延迟加载
ApplicationContext扩展接口,支持国际化、事件发布等
BeanDefinitionBean 的定义信息(类名、作用域、属性等)
BeanPostProcessorBean 后置处理器,可自定义初始化逻辑

1.3 Bean 的注册方式

1. XML 配置方式

xml
<bean id="userService" class="com.example.UserService">
    <property name="userDao" ref="userDao"/>
</bean>

2. 注解方式

java
@Component  // 通用组件
@Service    // 服务层
@Repository // 数据访问层
@Controller // 控制层

3. Java 配置方式

java
@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserService();
    }
}

4. 包扫描

java
@ComponentScan("com.example")
// 或
<context:component-scan base-package="com.example"/>

1.4 依赖注入方式

java
// 1. 构造器注入(推荐)
@Service
public class UserService {
    private final UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}

// 2. Setter 注入
@Service
public class UserService {
    private UserDao userDao;

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

// 3. 字段注入(不推荐,不利于测试)
@Service
public class UserService {
    @Autowired
    private UserDao userDao;
}

构造器注入优势:

  • 保证依赖不可变(final)
  • 保证依赖不为空
  • 便于单元测试
  • 完全初始化状态

二、Bean 生命周期

2.1 生命周期流程

┌──────────────────────────────────────────────────────────────┐
│                    Bean 生命周期完整流程                        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  1. 实例化 (Instantiation)                                   │
│     └─> 构造器创建 Bean 实例                                  │
│                                                              │
│  2. 属性赋值 (Populate)                                       │
│     └─> 依赖注入                                              │
│                                                              │
│  3. 初始化前处理                                              │
│     └─> BeanPostProcessor.postProcessBeforeInitialization() │
│                                                              │
│  4. 初始化 (Initialization)                                   │
│     ├─> @PostConstruct                                       │
│     ├─> InitializingBean.afterPropertiesSet()               │
│     └─> init-method                                          │
│                                                              │
│  5. 初始化后处理                                              │
│     └─> BeanPostProcessor.postProcessAfterInitialization()  │
│                                                              │
│  6. 使用 (In Use)                                            │
│     └─> Bean 处于就绪状态,可被调用                            │
│                                                              │
│  7. 销毁 (Destruction)                                        │
│     ├─> @PreDestroy                                          │
│     ├─> DisposableBean.destroy()                            │
│     └─> destroy-method                                       │
│                                                              │
└──────────────────────────────────────────────────────────────┘

2.2 生命周期代码示例

java
@Component
public class LifeCycleBean implements InitializingBean, DisposableBean {

    private String name;

    // 1. 构造器
    public LifeCycleBean() {
        System.out.println("1. 构造器执行");
    }

    // 2. 属性注入
    @Autowired
    public void setName(@Value("${app.name}") String name) {
        this.name = name;
        System.out.println("2. 属性注入: " + name);
    }

    // 3. 初始化前
    @PostConstruct
    public void postConstruct() {
        System.out.println("3. @PostConstruct 初始化前");
    }

    // 4. InitializingBean 接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("4. afterPropertiesSet()");
    }

    // 5. 自定义初始化方法
    @InitMethod
    public void customInit() {
        System.out.println("5. 自定义初始化方法");
    }

    // 6. 销毁前
    @PreDestroy
    public void preDestroy() {
        System.out.println("6. @PreDestroy 销毁前");
    }

    // 7. DisposableBean 接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("7. destroy()");
    }
}

2.3 BeanPostProcessor 扩展点

java
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        // 初始化前处理,如解析注解
        if (bean instanceof LifeCycleBean) {
            System.out.println("BeanPostProcessor - 初始化前处理");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        // 初始化后处理,如 AOP 代理
        if (bean instanceof LifeCycleBean) {
            System.out.println("BeanPostProcessor - 初始化后处理");
        }
        return bean;
    }
}

重要的 BeanPostProcessor:

处理器作用
AutowiredAnnotationBeanPostProcessor处理 @Autowired 注入
CommonAnnotationBeanPostProcessor处理 @Resource、@PostConstruct 等
ApplicationContextAwareProcessor注入 ApplicationContext
AbstractAutoProxyCreator创建 AOP 代理

三、AOP 实现原理

3.1 什么是 AOP

AOP(Aspect-Oriented Programming,面向切面编程) 将横切关注点(如日志、事务、权限)与业务逻辑分离。

java
// 传统方式:日志与业务耦合
public void transfer() {
    System.out.println("开始事务");
    // 业务逻辑
    System.out.println("提交事务");
}

// AOP 方式:关注点分离
@Transactional
public void transfer() {
    // 纯业务逻辑
}

3.2 AOP 核心概念

概念说明示例
切面(Aspect)横切关注点的模块化@Aspect 类
连接点(JoinPoint)程序执行的特定点方法调用、异常抛出
切点(Pointcut)匹配连接点的表达式execution(* com.example..(..))
通知(Advice)切面在特定点执行的动作@Before、@After、@Around
目标对象(Target)被通知的对象业务 Bean
代理(Proxy)AOP 创建的代理对象JDK 动态代理 / CGLIB

3.3 通知类型

java
@Aspect
@Component
public class LoggingAspect {

    // 前置通知:方法执行前
    @Before("execution(* com.example.service.*.*(..))")
    public void before(JoinPoint joinPoint) {
        System.out.println("方法执行前: " + joinPoint.getSignature().getName());
    }

    // 后置通知:方法执行后(无论是否异常)
    @After("execution(* com.example.service.*.*(..))")
    public void after(JoinPoint joinPoint) {
        System.out.println("方法执行后");
    }

    // 返回通知:方法成功返回后
    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("方法返回值: " + result);
    }

    // 异常通知:方法抛出异常后
    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex) {
        System.out.println("方法抛出异常: " + ex.getMessage());
    }

    // 环绕通知:最强大的通知类型
    @Around("execution(* com.example.service.*.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();

        try {
            Object result = joinPoint.proceed(); // 执行目标方法
            return result;
        } finally {
            long end = System.currentTimeMillis();
            System.out.println("方法执行耗时: " + (end - start) + "ms");
        }
    }
}

3.4 切点表达式

java
// 1. execution:匹配方法执行
execution(modifiers? return-type declaring-type? method-name(param-types) throws?)

// 示例
execution(public * com.example.service.*.*(..))    // service 包下所有公共方法
execution(* com.example..*.*(..))                   // com.example 及子包下所有方法
execution(* com.example.service.UserService.*(..))  // UserService 类的所有方法
execution(* com.example.service.*Service.*(..))     // 以 Service 结尾的类的所有方法
execution(* *(String, ..))                          // 第一个参数是 String 的方法

// 2. @annotation:匹配有特定注解的方法
@annotation(org.springframework.transaction.annotation.Transactional)

// 3. within:匹配特定类型
within(com.example.service.*)

// 4. @within:匹配有特定注解的类型
@within(org.springframework.stereotype.Service)

// 5. args:匹配参数类型
args(java.lang.String, ..)

// 6. 组合表达式
@Pointcut("execution(* com.example.service.*.*(..)) && args(id,..)")
public void serviceMethodWithId(Long id) {}

3.5 AOP 实现原理:动态代理

┌─────────────────────────────────────────────────────────────┐
│                     AOP 代理创建流程                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. AbstractAutoProxyCreator.postProcessAfterInitialization │
│     └─> Bean 初始化后,检查是否需要创建代理                    │
│                                                             │
│  2. 判断代理方式                                             │
│     ├─> 实现接口 -> JDK 动态代理                              │
│     └─> 未实现接口 -> CGLIB 代理                              │
│                                                             │
│  3. 创建代理对象                                             │
│     └─> 将通知织入代理对象                                    │
│                                                             │
│  4. 使用代理对象                                             │
│     └─> 方法调用时,先执行通知链                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

JDK 动态代理 vs CGLIB:

特性JDK 动态代理CGLIB 代理
原理反射机制字节码生成
要求必须实现接口可代理类
性能调用稍慢创建稍慢,调用快
限制只能代理接口方法不能代理 final 方法

配置代理方式:

java
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用 CGLIB
public class AopConfig {}

四、Spring 事务管理

4.1 事务特性(ACID)

特性说明
原子性(Atomicity)事务是不可分割的操作单位
一致性(Consistency)事务使数据库从一致状态转变为另一一致状态
隔离性(Isolation)多个事务并发执行时互不干扰
持久性(Durability)事务提交后,数据永久保存

4.2 事务隔离级别

java
public enum Isolation {
    DEFAULT,                // 使用数据库默认隔离级别
    READ_UNCOMMITTED,       // 读未提交(脏读、不可重复读、幻读)
    READ_COMMITTED,         // 读已提交(不可重复读、幻读)
    REPEATABLE_READ,        // 可重复读(幻读)
    SERIALIZABLE            // 串行化
}
隔离级别脏读不可重复读幻读
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ
SERIALIZABLE

4.3 事务传播行为

java
public enum Propagation {
    REQUIRED,       // 有事务则加入,无则新建(默认)
    SUPPORTS,       // 有事务则加入,无则以非事务运行
    MANDATORY,      // 必须在事务中运行,否则抛异常
    REQUIRES_NEW,   // 新建事务,挂起当前事务
    NOT_SUPPORTED,  // 以非事务运行,挂起当前事务
    NEVER,          // 以非事务运行,有事务则抛异常
    NESTED          // 嵌套事务(保存点)
}

传播行为示例:

java
@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private InventoryService inventoryService;

    // REQUIRED: 默认行为,保证整个方法在同一事务中
    @Transactional
    public void createOrder(Order order) {
        orderMapper.insert(order);
        inventoryService.decreaseStock(order.getProductId(), order.getQuantity());
    }
}

@Service
public class InventoryService {

    // REQUIRES_NEW: 独立事务,失败不影响外部事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void decreaseStock(Long productId, int quantity) {
        // 即使外部事务回滚,这里的库存扣减也会独立提交
    }

    // NESTED: 嵌套事务,可独立回滚
    @Transactional(propagation = Propagation.NESTED)
    public void logOperation(Long orderId) {
        // 失败可独立回滚,不影响外部事务
    }
}

4.4 事务失效场景

java
@Service
public class UserService {

    // 1. 方法非 public
    @Transactional
    private void method1() {} // 事务失效

    // 2. 同类方法调用(绕过代理)
    public void methodA() {
        this.methodB(); // 事务失效
    }
    @Transactional
    public void methodB() {}

    // 3. 异常被捕获
    @Transactional
    public void methodC() {
        try {
            // 业务代码
        } catch (Exception e) {
            // 异常被捕获,事务失效
        }
    }

    // 4. 异常类型不匹配
    @Transactional
    public void methodD() throws Exception {
        throw new Exception(); // 默认只回滚 RuntimeException
    }

    // 正确方式:指定回滚异常类型
    @Transactional(rollbackFor = Exception.class)
    public void methodE() throws Exception {
        throw new Exception(); // 正确回滚
    }
}

事务失效解决方案:

java
// 1. 注入自身(解决同类调用)
@Service
public class UserService {

    @Autowired
    private UserService self; // 注入自身代理

    public void methodA() {
        self.methodB(); // 通过代理调用
    }

    @Transactional
    public void methodB() {}
}

// 2. AopContext 获取代理
public void methodA() {
    ((UserService) AopContext.currentProxy()).methodB();
}

// 3. 拆分到不同 Service

4.5 事务实现原理

┌─────────────────────────────────────────────────────────────┐
│                  Spring 事务实现原理                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. AOP 代理                                                │
│     └─> TransactionInterceptor 拦截 @Transactional 方法     │
│                                                             │
│  2. 事务开启                                                │
│     ├─> 获取 DataSource                                     │
│     ├─> 创建 Connection                                     │
│     ├─> 设置 autoCommit = false                            │
│     └─> 绑定 Connection 到 ThreadLocal                      │
│                                                             │
│  3. 执行目标方法                                            │
│     └─> 从 ThreadLocal 获取同一 Connection                   │
│                                                             │
│  4. 事务提交/回滚                                           │
│     ├─> 正常返回 -> commit                                  │
│     └─> 异常 -> rollback                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

五、Spring Boot 自动配置原理

5.1 @SpringBootApplication 注解

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

// @SpringBootApplication 是组合注解
@SpringBootConfiguration  // 配置类
@EnableAutoConfiguration   // 启用自动配置
@ComponentScan             // 组件扫描
public @interface SpringBootApplication {}

5.2 @EnableAutoConfiguration 原理

┌─────────────────────────────────────────────────────────────┐
│                  自动配置加载流程                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. @EnableAutoConfiguration                                │
│     └─> @Import(AutoConfigurationImportSelector.class)      │
│                                                             │
│  2. AutoConfigurationImportSelector                         │
│     └─> 读取 META-INF/spring.factories                      │
│                                                             │
│  3. 加载自动配置类                                           │
│     └─> org.springframework.boot.autoconfigure.EnableAutoConfiguration │
│                                                             │
│  4. 条件过滤                                                │
│     ├─> @ConditionalOnClass                                │
│     ├─> @ConditionalOnBean                                  │
│     ├─> @ConditionalOnProperty                             │
│     └─> @ConditionalOnMissingBean                          │
│                                                             │
│  5. 注册生效的配置类                                         │
│     └─> 创建相应的 Bean                                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

5.3 自动配置示例

java
// DataSourceAutoConfiguration.java
@Configuration
@ConditionalOnClass(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public DataSource dataSource(DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().build();
    }
}

// application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456

5.4 条件注解

注解作用
@ConditionalOnClass类路径存在指定类时生效
@ConditionalOnMissingClass类路径不存在指定类时生效
@ConditionalOnBean容器中存在指定 Bean 时生效
@ConditionalOnMissingBean容器中不存在指定 Bean 时生效
@ConditionalOnProperty配置属性满足条件时生效
@ConditionalOnWebApplicationWeb 应用时生效
@ConditionalOnExpressionSpEL 表达式为 true 时生效

六、循环依赖解决

6.1 什么是循环依赖

java
@Service
public class ServiceA {
    @Autowired
    private ServiceB serviceB;
}

@Service
public class ServiceB {
    @Autowired
    private ServiceA serviceA;
}

6.2 三级缓存机制

java
// DefaultSingletonBeanRegistry

/** 一级缓存:完整的 Bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** 二级缓存:早期暴露的 Bean(已实例化,未初始化) */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

/** 三级缓存:Bean 工厂(用于生成早期 Bean) */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

6.3 解决流程

┌─────────────────────────────────────────────────────────────┐
│                    循环依赖解决流程                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 创建 ServiceA                                           │
│     └─> 实例化 A,放入三级缓存                               │
│                                                             │
│  2. 注入 ServiceA 的依赖 ServiceB                           │
│     └─> 发现 B 不存在,开始创建 B                            │
│                                                             │
│  3. 创建 ServiceB                                            │
│     └─> 实例化 B                                            │
│                                                             │
│  4. 注入 ServiceB 的依赖 ServiceA                            │
│     └─> 从三级缓存获取 A 的工厂,生成早期引用                  │
│     └─> 将 A 升级到二级缓存                                  │
│                                                             │
│  5. B 初始化完成,放入一级缓存                                │
│                                                             │
│  6. A 注入 B 成功,初始化完成,放入一级缓存                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

6.4 无法解决的循环依赖

java
// 1. 构造器注入(无法使用三级缓存)
@Service
public class ServiceA {
    public ServiceA(ServiceB serviceB) {} // 无法解决
}

// 2. 原型作用域(不使用缓存)
@Scope("prototype")
@Service
public class ServiceA {
    @Autowired
    private ServiceB serviceB; // 无法解决
}

// 解决方案:@Lazy
@Service
public class ServiceA {
    public ServiceA(@Lazy ServiceB serviceB) {
        this.serviceB = serviceB; // 延迟加载代理
    }
}

七、常见面试题

7.1 BeanFactory 和 ApplicationContext 的区别?

特性BeanFactoryApplicationContext
初始化延迟加载容器启动时加载
功能基础 IOC 功能国际化、事件发布、资源加载
性能占用内存少启动稍慢
适用场景资源受限环境企业级应用

7.2 Spring Bean 的作用域?

作用域说明
singleton单例(默认)
prototype每次获取创建新实例
request每个 HTTP 请求一个实例
session每个 HTTP Session 一个实例
applicationServletContext 生命周期内单例

7.3 @Autowired 和 @Resource 的区别?

特性@Autowired@Resource
来源SpringJSR-250
注入方式默认按类型默认按名称
指定名称@Qualifiername 属性
必需性required=false

7.4 Spring 如何解决事务并发问题?

java
// 乐观锁
@Version
private Integer version;

// 悲观锁
@Lock(LockModeType.PESSIMISTIC_WRITE)
private User user;

// 分布式锁
@Transactional
public void deductStock(Long productId) {
    String lockKey = "product:" + productId;
    try {
        if (redisLock.tryLock(lockKey, 30, TimeUnit.SECONDS)) {
            // 业务逻辑
        }
    } finally {
        redisLock.unlock(lockKey);
    }
}

八、总结

核心知识点

  1. IOC:控制反转,依赖注入,解耦对象创建
  2. Bean 生命周期:实例化 → 属性赋值 → 初始化 → 使用 → 销毁
  3. AOP:面向切面编程,动态代理实现横切关注点分离
  4. 事务管理:声明式事务,隔离级别,传播行为,失效场景
  5. 自动配置:条件注解,spring.factories,按需加载
  6. 循环依赖:三级缓存,构造器注入无法解决

最佳实践

  • 优先使用构造器注入
  • 合理设置事务隔离级别和传播行为
  • 避免循环依赖,使用 @Lazy 解耦
  • 理解 AOP 原理,避免事务失效

下一篇预告:Spring Boot 自动配置深入与源码解析

Released under the MIT License.