Java主流框架与源码:Spring Framework

1. 引言

Spring Framework 是 Java 生态中最核心、最基础的企业级应用开发框架。它通过**控制反转(IoC)面向切面编程(AOP)**两大核心理念,极大地简化了 Java 应用的开发与维护。无论是传统的 SSM 架构,还是当下流行的 Spring Boot、Spring Cloud 微服务体系,其底层都构建在 Spring Framework 之上。

本文将深入剖析 Spring Framework 的四大核心机制:IoC 容器与 Bean 生命周期AOP 动态代理事件驱动模型 ,以及面试高频考点------循环依赖的解决原理。通过源码级别的分析,帮助读者真正理解 Spring 的设计哲学,而不仅仅是停留在 API 的使用层面。

2. 核心概念:IoC 与 AOP

2.1 控制反转(IoC)

控制反转(Inversion of Control) 是一种设计原则,它将对象的创建、装配和管理的控制权从程序员手中转移到容器(Spring IoC Container)手中。传统开发中,我们通过 new 关键字主动创建对象并维护依赖关系;而在 Spring 中,我们只需声明依赖,容器负责在合适的时机创建 Bean 并注入依赖。

java 复制代码
// 传统方式:主动创建
public class UserService {
    private UserDao userDao = new UserDao();
}

// Spring 方式:声明式依赖注入
@Service
public class UserService {
    @Autowired
    private UserDao userDao;
}

2.2 面向切面编程(AOP)

面向切面编程(Aspect Oriented Programming) 允许我们将日志记录、事务管理、权限校验等横切关注点(Cross-cutting Concerns)从业务逻辑中剥离出来,通过动态代理在运行时织入。Spring AOP 默认基于 JDK 动态代理(接口代理)或 CGLIB(子类代理)实现。

java 复制代码
@Aspect
@Component
public class LogAspect {
    @Around("execution(* com.example.service.*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        System.out.println(joinPoint.getSignature().getName() + " 耗时: " + (System.currentTimeMillis() - start) + "ms");
        return result;
    }
}

3. IoC 容器与 Bean 生命周期源码解析

3.1 容器启动核心流程

Spring IoC 容器的核心入口是 ApplicationContext,其最经典的实现是 ClassPathXmlApplicationContext(XML 时代)和 AnnotationConfigApplicationContext(注解时代)。容器启动的核心方法为 refresh(),它定义了整个容器的初始化骨架:

java 复制代码
// AbstractApplicationContext.refresh()
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 准备刷新上下文
        prepareRefresh();
        // 2. 获取 BeanFactory(默认 DefaultListableBeanFactory)
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // 3. 准备 BeanFactory,设置类加载器、SpEL 解析器等
        prepareBeanFactory(beanFactory);
        // 4. 子类扩展点(如 Web 容器注册 Scope)
        postProcessBeanFactory(beanFactory);
        // 5. 执行 BeanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(beanFactory);
        // 6. 注册 BeanPostProcessor
        registerBeanPostProcessors(beanFactory);
        // 7. 初始化消息源(国际化)
        initMessageSource();
        // 8. 初始化事件广播器
        initApplicationEventMulticaster();
        // 9. 子类扩展点(如 Spring MVC 的 onRefresh)
        onRefresh();
        // 10. 注册监听器
        registerListeners();
        // 11. 实例化所有非懒加载的单例 Bean
        finishBeanFactoryInitialization(beanFactory);
        // 12. 完成刷新,发布 ContextRefreshedEvent
        finishRefresh();
    }
}

3.2 Bean 的完整生命周期

一个 Bean 从创建到销毁,会经历一系列回调。理解这一过程对排查问题至关重要:

3.3 三级缓存与循环依赖解决

循环依赖 是指 A 依赖 B,B 又依赖 A 的情况。Spring 通过三级缓存 机制解决了单例 Bean 的循环依赖问题。三级缓存定义在 DefaultSingletonBeanRegistry 中:

java 复制代码
// 一级缓存:成品 Bean(完全初始化好的单例)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

// 二级缓存:早期暴露的 Bean(已实例化但未完成属性填充)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

// 三级缓存:ObjectFactory 工厂(用于生成早期引用,支持 AOP 提前代理)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

解决流程(以 A 依赖 B、B 依赖 A 为例):

  1. 创建 A,实例化后将其 ObjectFactory 放入三级缓存 singletonFactories
  2. 填充 A 的属性时发现需要 B,于是去创建 B;
  3. B 实例化后同样放入三级缓存,填充属性时发现需要 A;
  4. B 从三级缓存中拿到 A 的 ObjectFactory,调用 getObject() 得到 A 的早期引用(若 A 需要 AOP,则在此生成代理对象),放入二级缓存,并注入给 B;
  5. B 完成初始化,放入一级缓存;
  6. 回到 A,从一级缓存拿到 B 并注入,A 完成初始化,放入一级缓存。
java 复制代码
// DefaultSingletonBeanRegistry.getSingleton() 核心逻辑
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
            synchronized (this.singletonObjects) {
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) {
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
    }
    return singletonObject;
}

注意 :三级缓存只能解决单例 + 非构造器注入 的循环依赖。构造器注入的循环依赖无法解决,会抛出 BeanCurrentlyInCreationException;原型(Prototype)作用域的 Bean 也不支持循环依赖。

4. AOP 动态代理原理

4.1 代理方式选择

Spring AOP 在 DefaultAopProxyFactory 中决定使用 JDK 动态代理还是 CGLIB:

  • JDK 动态代理 :目标类实现了接口时默认使用,基于 java.lang.reflect.Proxy,只能代理接口方法;
  • CGLIB 代理:目标类未实现接口时使用,通过生成目标类的子类来代理,可代理类方法(final 方法除外)。
java 复制代码
// DefaultAopProxyFactory.createAopProxy()
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);
    } else {
        return new JdkDynamicAopProxy(config);
    }
}

4.2 代理创建时机

AOP 代理的创建发生在 Bean 生命周期的**「初始化后」**阶段,即 AbstractAutoProxyCreator.postProcessAfterInitialization() 方法中。这也是为什么三级缓存中需要 ObjectFactory------当循环依赖发生时,AOP 代理需要在 Bean 完全初始化之前就暴露出去。

java 复制代码
// AbstractAutoProxyCreator.postProcessAfterInitialization()
public Object postProcessAfterInitialization(Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

5. 事件驱动模型

Spring 的事件驱动模型基于观察者模式,由事件(ApplicationEvent)发布者(ApplicationEventPublisher)监听器(ApplicationListener) 三部分组成。它实现了业务模块之间的解耦。

5.1 自定义事件与监听

java 复制代码
// 1. 定义事件
public class OrderCreatedEvent extends ApplicationEvent {
    private final Long orderId;
    public OrderCreatedEvent(Object source, Long orderId) {
        super(source);
        this.orderId = orderId;
    }
    public Long getOrderId() { return orderId; }
}

// 2. 定义监听器(方式一:实现接口)
@Component
public class OrderEventListener implements ApplicationListener<OrderCreatedEvent> {
    @Override
    public void onApplicationEvent(OrderCreatedEvent event) {
        System.out.println("收到订单创建事件,订单ID: " + event.getOrderId());
        // 发送短信、更新库存等
    }
}

// 3. 定义监听器(方式二:@EventListener 注解,推荐)
@Component
public class OrderEventAnnotationListener {
    @EventListener
    @Async  // 配合 @EnableAsync 实现异步监听
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("异步处理订单事件: " + event.getOrderId());
    }
}

// 4. 发布事件
@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;

    public void createOrder(Long orderId) {
        // 业务逻辑...
        publisher.publishEvent(new OrderCreatedEvent(this, orderId));
    }
}

5.2 事件广播机制源码

事件发布的核心是 SimpleApplicationEventMulticaster,它在 refresh()initApplicationEventMulticaster() 阶段被创建。发布事件时,广播器会根据事件类型匹配所有监听器并逐个调用:

java 复制代码
// SimpleApplicationEventMulticaster.multicastEvent()
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            // 异步执行
            executor.execute(() -> invokeListener(listener, event));
        } else {
            // 同步执行
            invokeListener(listener, event);
        }
    }
}

6. 常见面试题与总结

6.1 高频面试题

  1. Spring 如何解决循环依赖? 通过三级缓存,在 Bean 实例化后提前暴露 ObjectFactory,使依赖方能够获取到早期引用。仅支持单例 + setter/字段注入。
  2. 为什么需要三级缓存,二级不够吗? 二级缓存可以解决循环依赖,但无法处理「循环依赖 + AOP」的场景。三级缓存中的 ObjectFactory 允许在 Bean 未完全初始化时就生成 AOP 代理,保证代理对象的唯一性。
  3. Spring AOP 和 AspectJ 的区别? Spring AOP 是运行时增强(基于代理),只能作用于 Spring 管理的 Bean;AspectJ 是编译期/加载期织入,功能更强大但配置复杂。
  4. @Transactional 失效的场景有哪些? 方法非 public、同类内部调用(this 调用绕过代理)、异常被捕获未抛出、方法非 final(CGLIB 无法代理 final 方法)等。

6.2 总结

Spring Framework 之所以成为 Java 生态的基石,在于其非侵入式的设计理念:

  • IoC 容器 统一管理对象生命周期,降低耦合;
  • AOP 将横切逻辑模块化,提升代码复用;
  • 事件驱动 实现模块间异步解耦;
  • 三级缓存 巧妙解决循环依赖,体现了对 Bean 生命周期的精细控制。

理解这些底层原理,不仅能帮助我们写出更健壮的代码,更是深入 Spring Boot 自动装配、Spring Cloud 微服务治理的必经之路。建议读者结合源码(spring-beansspring-contextspring-aop 模块)动手调试,才能真正做到融会贯通。

相关推荐
yume_sibai2 小时前
03-Rust 函数式编程特性(闭包 + Iterator + Option/Result + 链式调用)
开发语言·后端·rust
吃饱了得干活2 小时前
Redis 不是死脑筋,它是一套“会进化”的存储系统
redis·后端
伩仁2 小时前
别再 HTTP 200 一把梭了:用 RFC 9457 Problem Details 给 FastAPI 错误响应"立规矩"
后端
MeetTanG2 小时前
Go 实战锦囊|errgroup:优雅地管理并发任务组
后端·go
PragmaticWorks2 小时前
DDD 学了很多却用不上?因为你把“责任”和“时机”揉在了一起
后端·领域驱动设计
凯哥Java3 小时前
System.setProperty 的正确姿势:Spring Boot 启动类里的“缺省值“魔法
java·spring boot·后端
柯克七七3 小时前
Vue刷新页面数据重置?一招解决Vuex状态丢失
后端
楚兴3 小时前
ACP 到底解决了什么?让 IDE 和 Coding Agent 解耦
人工智能·后端·架构
楚兴3 小时前
DeepSeek Harness 到底在做什么?拆开 Agent 的运行时
人工智能·后端·架构