Spring Framework

技术栈
后端框架
javaspringIoCDIAOP企业级

概览

Spring Framework

Spring Framework 是 Java 平台最核心的企业级应用框架,Spring Boot 的基石。

是什么

Spring 是一个轻量级的控制反转(IoC)和面向切面编程(AOP)的容器框架。最初由 Rod Johnson 在 2003 年创建,旨在解决 Java EE 开发的复杂性。

解决什么问题

  • 解耦:通过 IoC 容器管理对象依赖,代码松耦合
  • 简化 J2EE:无需 EJB 也能实现企业级功能
  • 统一编程模型:一致的模板模式(JdbcTemplate、RestTemplate 等)
  • AOP:声明式事务管理、日志、安全等横切关注点

关键特性

  • IoC 容器:BeanFactory / ApplicationContext
  • 依赖注入:构造器注入、Setter 注入、字段注入
  • AOP:面向切面编程,声明式事务
  • Spring MVC:Web 层框架
  • Spring JDBC:简化数据库操作
  • Spring Transaction:声明式事务管理

安装

Spring Framework 安装指南

1. 环境准备

操作系统

  • Windows / macOS / Linux 均可

JDK 版本

Spring Framework 版本 JDK 最低要求
Spring 6.x JDK 17+
Spring 5.x JDK 8+
Spring 4.x JDK 6 ~ 8

构建工具

  • Maven 3.6+
  • Gradle 7+

2. 安装步骤

Maven 依赖

<!-- pom.xml - Spring Context (核心 IoC) -->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.1.0</version>
    </dependency>

    <!-- Spring MVC(如需要 Web 功能) -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>6.1.0</version>
    </dependency>

    <!-- Spring JDBC(如需要数据库操作) -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>6.1.0</version>
    </dependency>
</dependencies>

Gradle 依赖

dependencies {
    implementation 'org.springframework:spring-context:6.1.0'
    implementation 'org.springframework:spring-webmvc:6.1.0'
    implementation 'org.springframework:spring-jdbc:6.1.0'
}

3. 常见安装问题

Q: 版本兼容性问题?

使用 Spring Boot 的 BOM(Bill of Materials)统一管理版本:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-framework-bom</artifactId>
            <version>6.1.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Q: 类找不到?

确保所有 Spring 模块版本一致,不同模块不应混用不同版本。

示例

Spring Framework IoC 容器示例

目标

演示 Spring IoC 容器的基本用法:Bean 定义、依赖注入、ApplicationContext 启动。

完整代码

1. 服务接口和实现

// MessageService.java
package com.example.service;

public interface MessageService {
    String getMessage();
}

// EmailService.java
package com.example.service.impl;

import com.example.service.MessageService;

public class EmailService implements MessageService {
    private String sender;

    // Setter 注入
    public void setSender(String sender) {
        this.sender = sender;
    }

    @Override
    public String getMessage() {
        return "Email from " + sender;
    }
}

// SmsService.java
package com.example.service.impl;

import com.example.service.MessageService;

public class SmsService implements MessageService {
    @Override
    public String getMessage() {
        return "SMS message";
    }
}

2. 消费者类

package com.example.consumer;

import com.example.service.MessageService;

public class NotificationConsumer {
    private MessageService messageService;

    // 构造器注入(推荐)
    public NotificationConsumer(MessageService messageService) {
        this.messageService = messageService;
    }

    public void notifyUser() {
        System.out.println(messageService.getMessage());
    }
}

3. XML 配置 beans.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">

    <bean id="emailService" class="com.example.service.impl.EmailService">
        <property name="sender" value="noreply@example.com"/>
    </bean>

    <bean id="smsService" class="com.example.service.impl.SmsService"/>

    <bean id="notificationConsumer" class="com.example.consumer.NotificationConsumer">
        <constructor-arg ref="emailService"/>
    </bean>
</beans>

4. Java Config 配置(注解方式)

package com.example.config;

import com.example.service.MessageService;
import com.example.service.impl.EmailService;
import com.example.consumer.NotificationConsumer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MessageService messageService() {
        EmailService service = new EmailService();
        service.setSender("noreply@example.com");
        return service;
    }

    @Bean
    public NotificationConsumer notificationConsumer() {
        return new NotificationConsumer(messageService());
    }
}

5. 主程序

package com.example;

import com.example.config.AppConfig;
import com.example.consumer.NotificationConsumer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        // 方式一:XML 配置
        ApplicationContext xmlCtx =
            new ClassPathXmlApplicationContext("beans.xml");
        NotificationConsumer consumer1 =
            xmlCtx.getBean(NotificationConsumer.class);
        consumer1.notifyUser();

        // 方式二:Java 注解配置
        ApplicationContext annoCtx =
            new AnnotationConfigApplicationContext(AppConfig.class);
        NotificationConsumer consumer2 =
            annoCtx.getBean(NotificationConsumer.class);
        consumer2.notifyUser();
    }
}

运行

javac -cp "spring-context-6.1.0.jar:..." com/example/*.java com/example/**/*.java
java -cp ".:spring-context-6.1.0.jar:spring-core-6.1.0.jar:spring-beans-6.1.0.jar:spring-expression-6.1.0.jar:commons-logging-1.2.jar" com.example.Main

预期输出

Email from noreply@example.com
Email from noreply@example.com

教程

Spring Framework 核心原理深入教程

第一章:IoC 容器深入

1.1 BeanFactory vs ApplicationContext

BeanFactory (接口)
 └── ApplicationContext (接口)
       ├── ClassPathXmlApplicationContext
       ├── FileSystemXmlApplicationContext
       ├── AnnotationConfigApplicationContext
       └── WebApplicationContext
特性 BeanFactory ApplicationContext
Bean 实例化 懒加载 预初始化(默认)
国际化 ✅ MessageSource
事件发布 ✅ ApplicationEvent
资源加载 ✅ ResourceLoader
使用场景 资源受限环境 生产环境推荐

1.2 Bean 生命周期

1. 实例化 (Instantiation)
2. 属性赋值 (Populate Properties)
3. BeanNameAware.setBeanName()
4. BeanFactoryAware.setBeanFactory()
5. ApplicationContextAware.setApplicationContext()
6. BeanPostProcessor.postProcessBeforeInitialization()
7. @PostConstruct / InitializingBean.afterPropertiesSet()
8. BeanPostProcessor.postProcessAfterInitialization()
9. Bean 就绪
10. @PreDestroy / DisposableBean.destroy() (容器关闭时)

1.3 作用域(Scope)

@Component
@Scope("singleton")   // 默认,整个容器一个实例
public class SingletonBean { }

@Component
@Scope("prototype")   // 每次获取创建新实例
public class PrototypeBean { }

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean { }  // Web 环境,每次 HTTP 请求

@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionScopedBean { }  // Web 环境,每次 HTTP Session

第二章:依赖注入详解

2.1 三种注入方式对比

// 1. 构造器注入(推荐)—— 不可变、强制依赖
@Component
public class ConstructorInjection {
    private final UserRepository repository;

    public ConstructorInjection(UserRepository repository) {
        this.repository = repository;
    }
}

// 2. Setter 注入 —— 可选依赖
@Component
public class SetterInjection {
    private Logger logger;

    @Autowired(required = false)
    public void setLogger(Logger logger) {
        this.logger = logger;
    }
}

// 3. 字段注入 —— 不推荐,难以测试
@Component
public class FieldInjection {
    @Autowired
    private UserRepository repository;
}

2.2 循环依赖

Spring 通过三级缓存解决单例 Setter 注入的循环依赖:

singletonObjects (一级缓存) → 完全初始化好的 Bean
earlySingletonObjects (二级缓存) → 早期引用(未完成属性填充)
singletonFactories (三级缓存) → Bean 工厂(可生成代理)

注意:构造器注入的循环依赖无法解决,会抛出 BeanCurrentlyInCreationException

第三章:AOP 面向切面编程

3.1 核心概念

概念 说明
Aspect 切面,横切关注点的模块化
Join Point 连接点,方法执行点
Advice 通知,切面在连接点的行为
Pointcut 切入点,匹配连接点的表达式
Weaving 织入,将切面应用到目标对象

3.2 声明式事务实现原理

@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
    // Spring AOP 在方法执行前后:
    // 1. 开启事务 (TransactionInterceptor)
    // 2. 执行业务方法
    // 3. 提交或回滚事务
}

Spring 使用 @TransactionalTransactionInterceptorPlatformTransactionManager 链式处理。默认通过 JDK 动态代理或 CGLIB 代理实现。

3.3 自定义切面

@Aspect
@Component
public class LoggingAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceLayer() {}

    @Before("serviceLayer()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("调用: " + joinPoint.getSignature().getName());
    }

    @Around("serviceLayer()")
    public Object measureTime(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        long elapsed = System.currentTimeMillis() - start;
        System.out.println("耗时: " + elapsed + "ms");
        return result;
    }
}

第四章:Spring MVC 请求处理流程

请求 → DispatcherServlet
       → HandlerMapping(找到 Handler + Interceptors)
       → HandlerAdapter(执行 Handler)
       → Handler(Controller)
       → 返回 ModelAndView
       → ViewResolver(解析视图)
       → View(渲染)
       → 响应

思考题

  1. 为什么构造器注入优于字段注入?
  2. Spring 三级缓存如何解决循环依赖,能否解决构造器注入的循环依赖?
  3. JDK 动态代理和 CGLIB 代理的区别,Spring 如何选择?
  4. 如何实现一个自定义 Spring Boot Starter?

参考资料

  1. [1] Spring Team. Spring Framework Documentation. 2024. https://docs.spring.io/spring-framework/reference/
  2. [2] Iuliana Cosmina, Rob Harrop, Chris Schaefer, et al.. Pro Spring 6. 2023.
  3. [3] 王福强. Spring 揭秘. 2009.