Spring 框架的核心是IOC(控制反转)和 AOP(面向切面编程),这两个特性是 Spring 所有功能的基础,也是它能解决 “代码耦合、通用逻辑冗余” 问题的核心。

1. IOC(控制反转)—— 解耦对象依赖

  • 核心思想:把对象的创建、依赖组装的权力从业务代码 “反转” 给 Spring 容器,而非由对象自己创建依赖;
  • 具体实现:依赖注入(DI)是 IOC 的落地方式(构造器注入、Setter 注入、字段注入);
  • 解决问题:传统开发中 UserService service = new UserServiceImpl() 这种硬编码创建对象的方式耦合度极高,IOC 让容器统一管理 Bean,替换实现类、调整依赖无需修改业务代码;
  • 实战举例:项目中所有 Service、Controller 都交给 Spring 容器管理,通过 @Autowired/ 构造器注入依赖,无需手动 new 对象,大幅降低耦合。

依赖注入是 Spring 核心 IOC(控制反转)的具体实现方式,指对象的依赖由 Spring 容器创建并注入,而非自身创建,核心是解耦。理解如下:

  • 传统开发中,对象需要自己创建依赖(如 UserService service = new UserServiceImpl()),耦合度高;
  • 依赖注入下,对象的依赖不再由自身创建,而是由 Spring 容器创建并 “注入” 到对象中
  • 本质是 “将对象的创建权交给容器,容器负责组装对象之间的依赖关系”,最终实现解耦(比如替换 UserService 的实现类,无需修改业务代码)。

依赖注入的 3 种核心方式

1.1. 构造器注入(推荐,Spring 官方首选)
  • 原理:通过类的构造方法注入依赖,Spring 会调用带参数的构造器,将容器中的 Bean 传入;
  • 优点:依赖不可变(构造后无法修改)、保证依赖非空(必须传入),避免空指针;
  • 实战代码:java运行
@Service
public class OrderService {
    // 依赖的对象
    private final UserService userService;

    // 构造器注入(Spring 5+ 可省略 @Autowired)
    public OrderService(UserService userService) {
        this.userService = userService;
    }
}
1.2. Setter 注入
  • 原理:通过类的 Setter 方法注入依赖,需配合 @Autowired 注解;
  • 优点:依赖可选(可随时修改),适合非必需的依赖;
  • 实战代码:java运行
@Service
public class OrderService {
    private UserService userService;

    // Setter注入
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}
1.3. 字段注入(便捷但不推荐)
  • 原理:直接在类的成员变量上标注 @Autowired,Spring 直接给字段赋值;
  • 优点:代码简洁、无需写构造器 / Setter;
  • 缺点:无法实现依赖不可变(字段可被修改)、单元测试难(需手动注入依赖)、可能导致空指针;
  • 实战代码:java运行
@Service
public class OrderService {
    // 字段注入
    @Autowired
    private UserService userService;
}
1.4. 另外:当一个接口有多个实现类时,需指定名称。

例:java运行

// 方式1:@Autowired + @Qualifier
@Autowired
@Qualifier("userServiceImplV2")
private UserService userService;

// 方式2:@Resource
@Resource(name = "userServiceImplV2")
private UserService userService;

2. AOP(面向切面编程)—— 抽离通用逻辑

AOP 是面向切面编程,把日志、权限、事务等通用逻辑抽成 “切面”,动态织入业务方法,不侵入业务代码,核心是解耦通用逻辑和业务逻辑。

  • 核心思想:将与业务无关的通用逻辑(日志、权限、事务、性能监控)抽成 “切面”,在不修改业务代码的前提下,动态织入到目标方法的指定位置(如方法执行前 / 后);
  • 解决问题:避免通用逻辑散落在各个业务方法中(如每个接口都写日志代码),实现 “一处定义、处处复用”;
  • 实战举例:用 @Transactional 注解实现声明式事务(底层是 AOP),用自定义切面实现接口统一日志打印,无需在每个 Controller 方法中写日志代码。
AOP 的底层是动态代理:
2.1、JDK 动态代理:被代理类实现接口时,用 JDK 动态代理(基于接口生成代理类);

        2.1.1 适用场景:被代理类实现了接口(如 Controller、Service 实现接口);

        2.1.2 核心原理:通过 java.lang.reflect.Proxy 类的 newProxyInstance() 方法,动态生成一个实现了目标接口的代理类;代理类持有 InvocationHandler 接口实现类,在调用目标方法时,先执行 InvocationHandler 的 invoke() 方法(切面逻辑),再调用目标方法;

        2.1.3 特点:基于接口,无需第三方依赖,JDK 原生支持。

2.2、CGLIB 动态代理:未实现接口时,用 CGLIB 动态代理(基于子类生成代理类);

        2.1 适用场景:被代理类没有实现接口(如自定义的工具类);

        2.2 核心原理:通过 ASM 字节码框架,动态生成目标类的子类作为代理类;重写目标方法,在重写的方法中先执行切面逻辑,再调用父类的目标方法;

        2.3 注意:由于是子类代理,目标方法不能是 final(final 方法无法被重写)。

2.3、Spring AOP 在运行时生成代理对象,调用目标方法时先执行切面逻辑,再执行原方法,实现无侵入增强。Spring AOP 的织入流程如下:(核心步骤)
  • 2.3.1 扫描切面:Spring 启动时,扫描标有 @Aspect 的切面类,解析 @Pointcut 切点和 @Before/@After 等通知;
  • 2.3.2 创建代理对象:对匹配切点的目标 Bean,Spring 不直接返回原 Bean,而是返回动态代理对象;
  • 2.3.3 方法调用:调用目标方法时,实际调用的是代理对象的方法,代理对象先执行切面逻辑(如日志、权限),再调用原目标方法;
  • 2.3.4 织入时机:Spring AOP 是运行时织入(区别于编译期织入、类加载期织入),只有在方法调用时才触发代理逻辑。
2.4、 Spring Boot 使用 AOP
  • 2.4.1 引入spring-boot-starter-aop依赖;
  • 2.4.2 编写切面类,用@Aspect + @Component标记;
  • 2.4.3 用@Pointcut定义切点(匹配指定方法 / 注解),用@Before/@After等定义通知;
  • 2.4.4 项目中常用 AOP 做接口日志、权限校验、接口耗时监控,大幅减少重复代码。

3. 补充

IOC 和 AOP 是基础,在此之上 Spring 扩展出其他核心能力:

  • 事务管理:基于 AOP 实现声明式事务,简化 begin/commit/rollback 操作;
  • Bean 生命周期管理:容器负责 Bean 的创建、初始化、销毁,支持自定义初始化 / 销毁逻辑;
  • 资源整合:统一整合 MyBatis、Redis、MQ 等第三方框架,通过 IOC 管理这些框架的组件。

总结

  1. Spring的核心双支柱:IOC 解决对象依赖耦合,AOP 解决通用逻辑冗余
  2. 落地价值:Spring 所有高级特性(事务、缓存、异步)都基于 IOC/AOP 实现;
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐