网站Logo Ilren 小记

Spring 核心机制深入解析:IOC 与 AOP 原理 + 实战 + 源码简析

jack
2
2024-01-06

Spring 是 Java 企业级开发的支柱,其成功很大程度归功于两个核心机制:IOC(控制反转)AOP(面向切面编程)。掌握这两个机制,不仅能写出更优雅的业务代码,还能理解 Spring 的设计哲学。

✅ 一、IOC(Inversion of Control)控制反转

1.1 什么是 IOC?

控制反转是一种设计思想,把对象的创建权从程序员转移到 Spring 容器,程序员只需要声明依赖,而无需关心对象是如何创建和管理的。

本质上就是“我不去 new 了,你容器帮我创建并注入”。

1.2 IOC 的两种主要实现方式

Spring 提供两种依赖注入方式:

注入方式

说明

构造方法注入

通过构造方法传入依赖

Setter/字段注入

通过 setter 方法或注解注入依赖(最常见)

1.3 IOC 示例

1)定义接口和实现类

public interface UserService {
    void register(String username);
}
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void register(String username) {
        System.out.println("注册用户:" + username);
    }
}

2)Controller 中注入依赖

@RestController
@RequestMapping("/user")
public class UserController {

    private final UserService userService;

    // 构造函数注入
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/register")
    public String register(@RequestParam String username) {
        userService.register(username);
        return "注册成功:" + username;
    }
}

Spring 容器会在项目启动时扫描带有 @Service 的类,并自动将其实例注入到 UserController 中。

1.4 IOC 的底层原理简析(源码角度)

IOC 的核心类是:ApplicationContext

  • 启动时,Spring 通过 AnnotationConfigApplicationContext 加载配置类。

  • 使用 反射 + 工厂模式 创建 Bean。

  • 将 Bean 存放在单例池(singletonObjects)中。

  • 通过 @Autowired 或构造器将依赖注入。

简化流程如下:

@Configuration
@ComponentScan
 --> ApplicationContext 启动
    --> 扫描 @Component、@Service、@Controller
        --> 创建 BeanDefinition
            --> 实例化(反射)
                --> 填充依赖

🔁 二、AOP(面向切面编程)

2.1 为什么需要 AOP?

在大型项目中,经常有一些横切关注点,比如:

  • 日志打印

  • 权限检查

  • 缓存处理

  • 异常监控

  • 性能统计

这些逻辑往往在多个业务方法中重复出现,难以维护。AOP 就是解决这类问题的理想方式。

2.2 AOP 核心概念

概念

含义

JoinPoint

连接点,Spring 只支持方法作为连接点

Pointcut

切入点,定义哪些连接点会被拦截

Advice

通知,增强逻辑,如前置通知、后置通知等

Aspect

切面,将切入点和通知封装成一个类

Weaving

编织,AOP 将增强逻辑“织入”到目标对象中的过程

2.3 AOP 示例:记录方法调用日志

1)引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2)定义切面类

@Aspect
@Component
public class LoggingAspect {

    // 切点:匹配 com.example.service 包下的所有方法
    @Pointcut("execution(* com.example.service..*(..))")
    public void logPointcut() {}

    // 前置通知
    @Before("logPointcut()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("[前置通知] 调用方法:" + joinPoint.getSignature());
    }

    // 后置通知
    @After("logPointcut()")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("[后置通知] 方法结束:" + joinPoint.getSignature());
    }

    // 返回后通知
    @AfterReturning(value = "logPointcut()", returning = "result")
    public void logReturn(Object result) {
        System.out.println("[返回通知] 返回值:" + result);
    }

    // 异常通知
    @AfterThrowing(value = "logPointcut()", throwing = "ex")
    public void logException(Throwable ex) {
        System.out.println("[异常通知] 异常信息:" + ex.getMessage());
    }

    // 环绕通知(最强大)
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed(); // 执行目标方法
        long end = System.currentTimeMillis();
        System.out.println("[环绕通知] 耗时:" + (end - start) + "ms");
        return result;
    }
}

2.4 AOP 的底层原理简析

Spring AOP 是基于 代理模式 实现的:

代理方式

适用情况

JDK 动态代理

目标对象实现了接口

CGLIB 代理

目标对象是普通类(没有接口)

原理流程如下:

  1. 容器扫描带 @Aspect 的切面类;

  2. 通过 ProxyFactoryBean 创建代理;

  3. 方法调用时,代理对象拦截方法并执行增强逻辑;

  4. 执行目标方法(proceed());

  5. 方法返回或异常时继续执行对应通知。

🧩 三、IOC 与 AOP 协同工作的过程

  1. Spring 容器加载所有 Bean;

  2. 检查是否有与 AOP 匹配的切点;

  3. 如果匹配,就生成代理类(使用 JDK/CGLIB);

  4. 注入到其它 Bean 中的是代理类而非原始类;

  5. 调用方法时,先进入代理类,再执行切面逻辑。

🛠 四、完整目录结构示意

src/main/java
└── com.example
    ├── aspect
    │   └── LoggingAspect.java
    ├── controller
    │   └── UserController.java
    ├── service
    │   ├── UserService.java
    │   └── UserServiceImpl.java
    └── Application.java

🚀 五、实战建议

  • 开发中,推荐使用构造函数注入(便于单元测试);

  • AOP 中环绕通知最灵活,但应谨慎使用;

  • 建议将切面逻辑模块化,比如:日志切面、事务切面、安全切面分开写;

  • 自定义注解结合 AOP 可实现更细粒度的控制。

📘 六、总结

特性

描述

IOC

控制对象创建和依赖注入,解耦模块

AOP

横切增强业务逻辑,关注核心业务

Spring 的精髓就在于这两个强大的机制,通过 IOC 解耦依赖,通过 AOP 解耦横切关注点,让我们专注于业务本身!

动物装饰