Skip to content

Spring Framework

plain
┌─────────────────────────────────────────────────────────┐
│                   Spring Framework                      │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │                  Spring Data Access                 │ │
│ │  (JDBC, ORM, JMS, Transactions, OXM)                │ │
│ └─────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │                  Spring Web Layer                   │ │
│ │  (Spring MVC, WebFlux, WebSocket, Portlet)          │ │
│ └─────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │                  Spring AOP & Instrumentation       │ │
│ │  (AOP, Aspects, Instrumentation)                    │ │
│ └─────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │              Spring Core Container (IoC/DI)         │ │
│ │  (Beans, Core, Context, SpEL)                       │ │
│ └─────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │                  Spring Test                        │ │
│ │  (TestContext, Mock Objects, MVC Test)              │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘

Core Container

模块功能说明
spring-core提供框架的基础工具类,包括资源加载、类型转换等
spring-beansBean 工厂和依赖注入的实现(BeanFactory, ApplicationContext)
spring-context扩展核心容器,添加事件传播、资源加载、国际化支持
spring-expressionSpEL(Spring Expression Language)表达式语言

AOP & Instrumentation

模块功能说明
spring-aop面向切面编程实现(基于代理)
spring-aspects集成 AspectJ 框架
spring-instrument类加载器工具,用于应用服务器集成

Data Access

模块功能说明
spring-jdbcJDBC 抽象层,简化数据库操作
spring-orm集成 ORM 框架(Hibernate, JPA, MyBatis)
spring-jmsJava 消息服务支持
spring-tx声明式事务管理(@Transactional)

Web Layer

模块功能说明
spring-webWeb 基础功能(文件上传、过滤器、HTTP 客户端)
spring-webmvc传统的 Spring MVC 框架(Servlet 基础)
spring-webflux响应式 Web 框架(Reactive Streams)
spring-websocketWebSocket 协议支持
  1. 加载配置 → XML/注解/Java Config
  2. 创建 BeanFactory → 解析 Bean 定义
  3. 实例化 Bean → 依赖注入(DI)
  4. 初始化 Bean → 执行生命周期回调
  5. 放入容器 → 单例池管理
  6. 应用使用 → 通过上下文获取 Bean

// 核心接口层次 BeanFactory (基础容器) ↓ ApplicationContext (高级容器) ↓ ├─ ClassPathXmlApplicationContext ├─ AnnotationConfigApplicationContext └─ WebApplicationContext

控制反转(IoC, Inversion of Control)

对象不再自己创建依赖,而是由外部容器把依赖"塞"进来。

plain
┌─────────────────────────────────────────┐
│ ApplicationContext extends BeanFactory  │
│                                         │
├─────────────────────────────────────────┤
│  • 国际化支持 (MessageSource)             │
│  • 事件传播 (ApplicationEventPublisher)  │
│  • 资源加载 (ResourceLoader)             │
│  • 自动装配 (AutowireCapable)            │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│           BeanFactory                   │
│    (基础容器,核心 IoC 功能)              │
├─────────────────────────────────────────┤
│  • Bean 定义管理 (BeanDefinition)        │
│  • Bean 实例化 & 生命周期管理              │
│  • 依赖解析 & 注入                        │
└─────────────────────────────────────────┘
实现类使用场景
ClassPathXmlApplicationContextXML 配置(传统)
AnnotationConfigApplicationContext注解/Java Config(主流)
WebApplicationContextWeb 应用环境

依赖注入(DI, Dependency Injection)

  • 构造器注入(推荐)
  • Setter 注入
  • 字段注入(常见,但不推荐)

FactoryBean 与 BeanFactory

特性BeanFactoryFactoryBean
本质Spring 的核心容器接口一种特殊的 Bean
职责负责管理和创建所有 Bean负责自定义创建特定 Bean 的过程
地位基础设施,IoC 容器的基础扩展点,允许开发者介入 Bean 创建
获取方式applicationContext.getBean()作为普通 Bean 注入使用

Bean

懒加载

单实例Bean会在容器启动时立即实例化并加载到Spring容器中。然而,有时我们希望延迟加载某些Bean,直到它们第一次被调用时才进行实例化。为此,Spring提供了懒加载机制。

@Lazy、XML 中lazy-init="true

Bean 作用域

作用域说明使用场景
singleton(默认)每个 Spring 容器只有一个实例无状态服务、配置类
prototype每次获取都创建新实例有状态对象
request每个 HTTP 请求一个实例Web 应用
session每个 HTTP Session 一个实例用户会话数据
applicationServletContext 生命周期全局应用数据

FactoryBean

定义:一个接口,当 Bean 实现了该接口时,Spring 容器不会直接返回该 Bean 实例,而是返回其 getObject() 方法创建的对象。

java
public interface FactoryBean<T> {
    T getObject() throws Exception;      // 返回实际创建的 Bean
    Class<?> getObjectType();            // 返回创建 Bean 的类型
    boolean isSingleton();               // 是否为单例
}

// 例如, Mybatis MybatisSqlSessionFactoryBean
public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
    public SqlSessionFactory getObject() throws Exception {
        if (this.sqlSessionFactory == null) {
            this.afterPropertiesSet();
        }

        return this.sqlSessionFactory;
    }
}

Bean 生命周期

plain
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  加载配置    │ ──→ │ 解析 Bean   │ ──→ │ 注册 Bean   │
│ (XML/注解)   │     │ 定义信息     │     │ Definition  │
└─────────────┘     └─────────────┘     └──────┬──────┘

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  放入容器    │ ←── │ 初始化回调   │ ←── │  属性注入    │
│ (单例池)     │     │ (生命周期)   │     │ (DI 完成)   │
└─────────────┘     └─────────────┘     └─────────────┘

1. 实例化(Instantiation)
   ↓ 调用构造器
2. 属性赋值(Populate)
   ↓ 依赖注入
3. 初始化(Initialization)
   ↓ 执行初始化方法
   ├─ @PostConstruct
   ├─ InitializingBean.afterPropertiesSet()
   └─ 自定义 init-method
4. Bean 就绪,放入单例池
   ↓ 使用
5. 销毁(Destruction)
   ↓ 容器关闭时
   ├─ @PreDestroy
   ├─ DisposableBean.destroy()
   └─ 自定义 destroy-method

示例

java
@Component
public class MyBean implements InitializingBean, DisposableBean {
    
    @PostConstruct
    public void postConstruct() {
        System.out.println("1. @PostConstruct");
    }
    
    @Override
    public void afterPropertiesSet() {
        System.out.println("2. InitializingBean");
    }
    
    public void customInit() {
        System.out.println("3. 自定义 init");
    }
    
    // ========== 销毁阶段 ==========
    
    @PreDestroy
    public void preDestroy() {
        System.out.println("1. @PreDestroy");
    }
    
    @Override
    public void destroy() {
        System.out.println("2. DisposableBean");
    }
    
    public void customDestroy() {
        System.out.println("3. 自定义 destroy");
    }
}

循环依赖解决

构造器注入的循环依赖无法解决(因为实例化阶段就需要依赖)。

缓存级别名称存储内容
一级singletonObjects完全初始化好的 Bean
二级earlySingletonObjects提前暴露的 Bean(未填充属性)
三级singletonFactoriesBean 工厂(用于创建代理)
plain
// A → B → A 的循环依赖场景
A 实例化 → 放入三级缓存 → A 属性注入发现需要 B

B 实例化 → B 属性注入发现需要 A → 从三级缓存取 A 的工厂

                    B 初始化完成 → A 继续初始化

Bean Proxy

plain
┌─────────────────────────────────────────────────────────────┐
│                    Bean 创建 & 代理流程                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 扫描 @Component → BeanDefinition                        │
│                    ↓                                         │
│  2. 实例化 Bean(反射调用构造器)                             │
│     UserService userService = new UserService();            │
│                    ↓                                         │
│  3. 依赖注入(populateBean)                                   │
│     userService.dao = @Autowired 的 UserDao                 │
│                    ↓                                         │
│  4. 初始化(initializeBean)                                  │
│     ├─ @PostConstruct                                        │
│     ├─ afterPropertiesSet()                                  │
│     └─ init-method                                          │
│                    ↓                                         │
│  5. 【AOP 代理创建】BeanPostProcessor                        │
│     AbstractAutoProxyCreator.postProcessAfterInitialization() │
│                    ↓                                         │
│     5.1 查找匹配的 Advisor(@Transactional, @Aspect等)        │
│                    ↓                                         │
│     5.2 创建 ProxyFactory                                    │
│                    ↓                                         │
│     5.3 选择代理类型                                          │
│         ├─ 有接口 → JdkDynamicAopProxy                        │
│         └─ 无接口 → ObjenesisCglibAopProxy                    │
│                    ↓                                         │
│     5.4 生成代理类字节码                                       │
│         ├─ JDK: ProxyGenerator.generateProxyClass()          │
│         └─ CGLIB: Enhancer.create() → ASM 生成子类           │
│                    ↓                                         │
│  6. 将代理对象放入单例池(singletonObjects)                   │
│     注意:此时容器中存的是代理,不是原始 Bean!                   │
│                    ↓                                         │
│  7. @Autowired 注入到其他 Bean 的是代理对象                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

配置方式演进

XML 配置(Spring 1.x/2.x)

xml
<beans>
    <bean id="userService" class="com.example.UserService">
        <constructor-arg ref="userRepository"/>
    </bean>
    <bean id="userRepository" class="com.example.UserRepository"/>
</beans>

注解配置(Spring 2.5+)

java
@Configuration
@ComponentScan("com.example")
public class AppConfig {
    
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

Spring Boot 自动配置(现代)

java
@SpringBootApplication  // 包含 @ComponentScan + @EnableAutoConfiguration
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

面向方面编程(AOP, Aspect-Oriented Programming)

AbstractAutoProxyCreator(AOP 核心类)

plain
┌─────────────────────────────────────────────────────────┐
│                    AOP 核心架构                          │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ┌─────────────────┐    ┌─────────────────┐           │
│  │   @Aspect 切面    │───→│   Advisor       │           │
│  │  (开发者定义)    │    │  (Spring 内部)  │           │
│  └─────────────────┘    └────────┬────────┘           │
│                                    │                     │
│                                    ↓                     │
│                           ┌─────────────────┐           │
│                           │  PointcutAdvisor │           │
│                           │  ├─ pointcut     │           │
│                           │  └─ advice       │           │
│                           └────────┬────────┘           │
│                                    │                     │
│                                    ↓                     │
│  ┌─────────────────────────────────────────────────┐   │
│  │           ProxyFactory(创建代理)                 │   │
│  │  ┌─────────────────┐    ┌─────────────────┐      │   │
│  │  │ JdkDynamicAopProxy│ or │ CglibAopProxy   │      │   │
│  │  │  (基于接口)     │    │  (基于继承)     │      │   │
│  │  └─────────────────┘    └─────────────────┘      │   │
│  └─────────────────────────────────────────────────┘   │
│                                    │                     │
│                                    ↓                     │
│                           ┌─────────────────┐           │
│                           │   代理对象        │           │
│                           │  (客户端使用)    │           │
│                           └─────────────────┘           │
│                                                         │
└─────────────────────────────────────────────────────────┘

Spring AOP 核心流程

plain
┌─────────────────────────────────────────────────────────────┐
│                     Spring AOP 完整流程                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 解析 @Aspect 切面类                                       │
│     ↓ AnnotationAwareAspectJAutoProxyCreator                 │
│                                                             │
│  2. 提取 @Pointcut 切点表达式                                │
│     ↓ AspectJExpressionPointcut                            │
│                                                             │
│  3. 提取 @Before/@Around 等通知方法                          │
│     ↓ 封装为 Advisor(Pointcut + Advice)                     │
│                                                             │
│  4. Bean 实例化后,匹配适用的 Advisor                         │
│     ↓ AbstractAutoProxyCreator.postProcessAfterInitialization│
│                                                             │
│  5. 创建代理对象                                              │
│     ├─ 有接口 → JDK 动态代理(JdkDynamicAopProxy)            │
│     └─ 无接口 → CGLIB 代理(CglibAopProxy)                   │
│                                                             │
│  6. 代理对象方法调用                                           │
│     ↓ ReflectiveMethodInvocation.proceed()                 │
│     ↓ 递归执行拦截器链(MethodInterceptor Chain)             │
│     ↓ 最终调用目标方法                                        │
│                                                             │
│  7. 返回结果                                                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Spring Aop 无法拦截的场景

java
// ❌ 无法拦截以下场景(因为基于代理)
public class UserService {
    
    // 1. 同类内部调用(this 不是代理)
    public void methodA() {
        this.methodB();  // @Transactional 失效!
    }
    
    @Transactional
    public void methodB() {}
    
    // 2. 非 public 方法(CGLIB 可以,但默认不代理)
    @Transactional
    private void privateMethod() {}  // 无法拦截
    
    // 3. 静态方法
    @Transactional
    public static void staticMethod() {}  // 无法拦截
    
    // 4. final 方法(CGLIB 无法重写)
    @Transactional
    public final void finalMethod() {}  // 无法拦截
}

内部调用失效原理

plain
┌─────────────────────────────────────────────────────────────┐
│                    同类内部调用失效原理                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   根本原因:                                                 │
│   this 指向的是原始目标对象(Target),                      │
│   而不是 Spring 容器中的代理对象(Proxy)。                   │
│                                                             │
│   ┌─────────┐      注入      ┌─────────┐                 │
│   │  客户端   │ ───────────────→ │  代理对象  │                 │
│   └─────────┘                  │  Proxy  │                 │
│                                └────┬────┘                 │
│                                     │ 调用 target           │
│                                ┌────┴────┐                 │
│                                │ 原始对象  │                 │
│                                │ Target  │                 │
│                                │         │                 │
│                                │ this.   │ ──→ 直接调用,   │
│                                │ method()│     不走代理!   │
│                                └─────────┘                 │
│                                                             │
│   解决方案优先级:                                            │
│   1. 拆分到不同类(最佳实践)                                  │
│   2. 注入自身代理(简单快速)                                  │
│   3. 使用 AopContext(需要 exposeProxy=true)               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

示例

启动 AOP

java
@Configuration
@EnableAspectJAutoProxy  // 开启 AOP 自动代理
public class AopConfig {
}

@PointCut 使用

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

表达式含义
execution(* *(..))拦截所有方法
execution(public * *(..))所有 public 方法
execution(* set*(..))所有 set 开头的方法
execution(* com.example.service.*.*(..))service 包下所有类的所有方法
execution(* com.example.service..*.*(..))service 包及其子包下所有方法
execution(* com.example.service.UserService.*(..))UserService 的所有方法
execution(String com.example.service.UserService.save*(..))返回 String 且 save 开头
execution(* save*(String, ..))第一个参数是 String 的 save 方法
org.aspectj.lang.annotation.@Aspect 自定义切面编程
java
@Aspect          // 声明为切面
@Component       // 交给 Spring 管理
public class LoggingAspect {
    
    // ========== 切点定义(复用)==========
    
    // 拦截 UserService 的所有方法
    @Pointcut("execution(* com.example.service.UserService.*(..))")
    public void userServiceMethods() {}
    
    // 拦截所有 @Transactional 方法
    @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
    public void transactionalMethods() {}
    
    // 组合切点:UserService 中有事务注解的方法
    @Pointcut("userServiceMethods() && transactionalMethods()")
    public void userServiceTxMethods() {}
    
    // ========== 通知实现 ==========
    
    // 前置通知
    @Before("userServiceMethods()")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        log.info("[BEFORE] 方法 {} 被调用,参数:{}", methodName, Arrays.toString(args));
    }
    
    // 环绕通知(最强大,可控制目标方法执行)
    @Around("transactionalMethods()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        
        try {
            log.info("[AROUND-BEFORE] 开始执行 {}", methodName);
            
            // 执行目标方法(关键!不调用则目标方法不会执行)
            Object result = joinPoint.proceed();
            
            long duration = System.currentTimeMillis() - start;
            log.info("[AROUND-AFTER] {} 执行成功,耗时 {}ms,返回值:{}", 
                    methodName, duration, result);
            
            return result;
            
        } catch (Exception e) {
            log.error("[AROUND-EXCEPTION] {} 执行失败: {}", methodName, e.getMessage());
            throw e;  // 必须抛出,否则异常被吞掉
        }
    }
    
    // 返回后通知
    @AfterReturning(pointcut = "userServiceMethods()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        log.info("[AFTER-RETURNING] 方法 {} 返回:{}", 
                joinPoint.getSignature().getName(), result);
    }
    
    // 异常通知
    @AfterThrowing(pointcut = "userServiceMethods()", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
        log.error("[AFTER-THROWING] 方法 {} 抛出异常:{}", 
                joinPoint.getSignature().getName(), ex.getMessage());
    }
    
    // 最终通知(类似 finally)
    @After("userServiceMethods()")
    public void logAfter(JoinPoint joinPoint) {
        log.info("[AFTER] 方法 {} 执行结束", joinPoint.getSignature().getName());
    }
}

自定义-AOP 访问限流

java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    int maxRequests() default 100;      // 最大请求数
    int timeWindow() default 60;        // 时间窗口(秒)
    String key() default "";            // 限流 key(支持 SpEL)
}

@Aspect
@Component
public class RateLimitAspect {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    @Around("@annotation(rateLimit)")
    public Object around(ProceedingJoinPoint point, RateLimit rateLimit) throws Throwable {
        // 1. 获取限流 key
        String key = generateKey(point, rateLimit);
        
        // 2. Redis 滑动窗口限流
        Long current = redisTemplate.opsForZSet().size(key);
        
        if (current != null && current >= rateLimit.maxRequests()) {
            throw new RateLimitException("请求过于频繁,请稍后再试");
        }
        
        // 3. 记录本次请求
        long now = System.currentTimeMillis();
        redisTemplate.opsForZSet().add(key, UUID.randomUUID().toString(), now);
        redisTemplate.expire(key, rateLimit.timeWindow(), TimeUnit.SECONDS);
        
        // 4. 清理过期数据(滑动窗口)
        redisTemplate.opsForZSet().removeRangeByScore(key, 0, now - rateLimit.timeWindow() * 1000);
        
        // 5. 执行目标方法
        return point.proceed();
    }
    
    private String generateKey(ProceedingJoinPoint point, RateLimit rateLimit) {
        // 实现 SpEL 解析,生成动态 key
        String methodName = point.getSignature().getName();
        return "rate_limit:" + methodName;
    }
}

@RestController
public class ApiController {
    
    @RateLimit(maxRequests = 10, timeWindow = 60)  // 每分钟最多10次
    @GetMapping("/api/sensitive")
    public String sensitiveApi() {
        return "敏感数据";
    }
}