Spring 框架的核心基础:IoC 和 AOP

news2025/4/15 11:41:48

一、IoC(Inversion of Control,控制反转)

定义:

IoC(Inversion of Control,控制反转),就是把对象创建和依赖关系的管理交给 Spring 容器,而不是由程序员手动去创建对象和管理依赖。
在这里插入图片描述

IoC 以前是我们想要什么就自己创建什么,现在是我们需要什么容器就帮我们送来什么。
在这里插入图片描述

举例:

以前:

UserService userService = new UserServiceImpl();

现在:

@Autowired
UserService userService;

Spring 帮忙创建并注入了这个对象,这就叫 控制反转(IoC)

Spring 倡导的开发方式就是这样,所有类的创建和销毁都通过 Spring 容器来,不再是开发者去 new,去 = null,这样就实现了对象的解耦。

于是,对于某个对象来说,以前是它控制它依赖的对象,现在是所有对象都被 Spring 控制。
在这里插入图片描述

说说什么是 DI?

定义:

IoC 是一种思想,DI 是实现 IoC 的具体方式,将一个对象所依赖的其他对象 以参数的形式传入,由外部容器(如 Spring)来“注入”依赖,而不是对象自己创建。

打个比方,你现在想吃炒菜和饭,点个外卖这时候就有人把炒好的菜和煮好的饭送到你手上。就好像 A 类需要 B 类,以前是 A 类自己 new 一个 B 类,现在是有人把 B 类送给到 A 类里。

常见方式:

  • 构造方法注入
  • Setter 方法注入
  • 字段注入(推荐使用构造注入)

举例(构造注入):

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

Spring 会自动将 UserRepository 注入。

为什么要使用 IoC 呢?

  1. 解耦:让对象的创建和管理交给 Spring 容器,降低对象之间的耦合度。
  2. 提高可维护性:对象的依赖关系由 Spring 统一管理,方便修改和扩展。

总结

IoC(Inversion of Control) 指的是控制反转,将对象创建和依赖关系都交给 Spring 容器去做;DI(Dependency Injection) 指的是依赖注入,是 IoC 的具体实现方式,包括构造方法、setter 方法和注解方式注入;使用IoC 是为了降低对象间的耦合度和方便修改和扩展。


Spring IoC 容器运行机制的核心之一:Bean 的生命周期

完整生命周期流程图分为五个阶段:
在这里插入图片描述

  • 实例化:Spring 首先使用构造方法或者工厂方法创建一个 Bean 的实例。在这个阶段,Bean 还没有被依赖注入。
  • 属性赋值:Spring 根据配置文件,将所有所需的属性值或依赖的 Bean 注入到该 Bean 中。这个过程称为依赖注入。
  • 初始化:在 Bean 依赖注入完成后,Spring 允许 Bean 进行初始化,可以在这里执行一些启动逻辑。(Spring 调用 afterPropertiesSet 方法,或通过配置文件指定的 init-method 方法,完成初始化。)
  • 使用中:Bean 准备好可以使用了。
  • 销毁:在容器关闭时,Spring 会调用 destroy 方法,完成 Bean 的清理工作。
实例化
   ↓
属性赋值(依赖注入)
   ↓
调用 BeanNameAware / BeanFactoryAware 等
   ↓
调用初始化方法(如 @PostConstruct、afterPropertiesSet())
   ↓
Bean 准备就绪,可被使用
   ↓
容器关闭前调用销毁方法(如 @PreDestroy、destroy())
从源码角度来讲:

在这里插入图片描述

  • 实例化:Spring 容器根据 Bean 的定义创建 Bean 的实例,相当于执行构造方法,也就是 new 一个对象。
  • 属性赋值:相当于执行 setter 方法为字段赋值。
  • 初始化:初始化阶段允许执行自定义的逻辑,比如设置某些必要的属性值、开启资源、执行预加载操作等,以确保 Bean 在使用之前是完全配置好的。
  • 销毁:相当于执行 = null,释放资源。

可以在源码 AbstractAutowireCapableBeanFactory 中的 doCreateBean 方法中,看到 Bean 的前三个生命周期:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
    }

    if (instanceWrapper == null) {
        // 实例化阶段
        instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    }

    ...

    Object exposedObject = bean;

    try {
        // 属性赋值阶段
        this.populateBean(beanName, mbd, instanceWrapper);
        // 初始化阶段
        exposedObject = this.initializeBean(beanName, exposedObject, mbd);
    } catch (Throwable var18) {
        ...
    }

    ...
}

在这里插入图片描述
源码位置,见下图:
在这里插入图片描述
至于销毁,是在容器关闭的时候调用的,详见 ConfigurableApplicationContextclose 方法。
在这里插入图片描述

二、AOP(Aspect-Oriented Programming,面向切面编程)

定义:

AOP,也就是面向切面编程,将业务逻辑中一些 通用的功能逻辑(如日志、事务、权限)从业务逻辑中抽离,统一切入到一个独立的模块中,让业务逻辑更加清爽,提高代码复用性和解耦性。
在这里插入图片描述

核心概念:

名称含义
JoinPoint程序执行的某个点,如方法调用
Pointcut切入点,匹配 JoinPoint 的规则
Advice要执行的逻辑,如 before/after/around
Aspect切面,通知和切入点的组合
Weaving将切面织入到目标对象的过程

举例:

场景:给 Service 方法统一加上日志

我们有一个 UserService,每次调用它的方法前都想打印日志,比如:

[Log] 正在调用方法:getUserById

1、创建业务类

@Service
public class UserService {
    public String getUserById(Long id) {
        System.out.println("正在执行 getUserById 业务逻辑");
        return "用户ID:" + id;
    }
}

2、创建切面类(日志功能)

@Aspect
@Component
public class LogAspect {

    // 切点:拦截所有 UserService 的方法
    @Pointcut("execution(* com.example.service.UserService.*(..))")
    public void userServiceMethods() {}

    // 前置通知:方法执行前打印日志
    @Before("userServiceMethods()")
    public void logBefore(JoinPoint joinPoint) {
        String method = joinPoint.getSignature().getName();
        System.out.println("[Log] 正在调用方法:" + method);
    }

    // 后置通知:方法执行完后打印
    @AfterReturning(pointcut = "userServiceMethods()", returning = "result")
    public void logAfter(JoinPoint joinPoint, Object result) {
        System.out.println("[Log] 方法执行完成,返回结果:" + result);
    }
}

3、开启 AOP 功能(Spring Boot 自动开启)

确保 Spring Boot 项目中依赖了 spring-boot-starter-aop

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

4、运行效果

调用如下代码:

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/user/{id}")
    public String getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}

控制台输出:

[Log] 正在调用方法:getUserById
正在执行 getUserById 业务逻辑
[Log] 方法执行完成,返回结果:用户ID:123

总结一句话:

AOP 是在 不改动源码的情况下 给程序添加额外功能(日志、事务、监控等)。


IoC、DI、AOP 对比:

概念一句话解释
IoC把对象的创建和管理交给 Spring 容器
DISpring 容器负责把依赖“注入”到类中
AOP给程序动态添加功能,而不改动源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2332174.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot 基础知识,HTTP 概述

1. 概述 1.1 Spring Spring 提供若干个子项目&#xff0c;每个项目用于完成特定功能 Spring 的若干个子项目都基于一个基础的框架&#xff1a;Spring Framework 框架类似于 房屋的地基 但 Spring Framework 配置繁琐&#xff0c;入门难度大 1.2 Spring Boot 于是&#xf…

《网络管理》实践环节04:SNMP监控数据采集流程及SNMP协议详细分析

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 1 实验目标 1. 理解SNMP网络管理原理 2. 掌握SNMP服务器采集SNMP Agent数据的方法 3. 掌握SNMP报文发送和应答流程 4. 掌握典型GetResponsePDU数据结构分析的方法 4. 具备SNMP通信…

《Uniapp-Vue 3-TS 实战开发》构建HTTP请求拦截器

引言 在 UniApp 结合 TypeScript 和 Vue3 的项目开发中&#xff0c;请求拦截器起着至关重要的作用。它能够在请求发送前和响应接收后对数据进行统一处理&#xff0c;极大地提高了代码的可维护性和功能性。本文将详细解析上述代码中请求拦截器的实现及其在 UniApp-Ts-Vue3 项目中…

从PDF中提取表格:以GB/T2260—2007为例

文章目录 先说结论前因后果思路1、PDF2CSV2、PDF2MD → MD2CSV3、针对不同表格的两种思路1&#xff09; 竖形三线表2&#xff09;五元素为一组 还没结束批量处理1、分割markdown文档2、跳过另一种格式的文档 总结一下 先说结论 结论就是&#xff0c;博主用了一天的时间去研究如…

初识MySQL · 复合查询(内外连接)

目录 前言&#xff1a; 基本查询回顾 笛卡尔积和子查询 笛卡尔积 内外连接 子查询 单行子查询 多行子查询 多列子查询 from中使用子查询 合并查询 前言&#xff1a; 在前文我们学习了MySQL的基本查询&#xff0c;就是简单的套用了select语句&#xff0c;最多不过是…

辛格迪客户案例 | 北京舒曼德医药实施电子合约系统(eSign)

01 北京舒曼德医药科技开发有限公司&#xff1a;医药科技的数字化先锋 北京舒曼德医药科技开发有限公司&#xff08;以下简称“舒曼德医药”&#xff09;作为国内医药科技领域的领军企业&#xff0c;致力于创新药物的研发、临床试验和市场推广。公司以“科技兴药、质量为先、服…

Python面向对象-开闭原则(OCP)

1. 什么是开闭原则&#xff1f; 开闭原则(Open-Closed Principle, OCP) 是面向对象设计的五大SOLID原则之一&#xff0c;由Bertrand Meyer提出。其核心定义是&#xff1a; “软件实体(类、模块、函数等)应该对扩展开放&#xff0c;对修改关闭。” 对扩展开放&#xff1a;当需求…

Class 文件和类加载机制

一、Class 文件 与 类加载机制 概述 什么是 Class 文件&#xff1f; Java 源码&#xff08;.java&#xff09;经过 javac 编译器 编译生成的字节码文件&#xff08;.class&#xff09;&#xff1b;由 JVM 识别执行&#xff0c;包含类的完整结构信息&#xff08;如字段、方法、…

Vue3+Vite+TypeScript+Element Plus开发-07.Mockjs引用与Axios封装

系列文档目录 Vue3ViteTypeScript安装 Element Plus安装与配置 主页设计与router配置 静态菜单设计 Pinia引入 Header响应式菜单缩展 Mockjs引用与Axios封装 登录设计 登录成功跳转主页 多用户动态加载菜单 Pinia持久化 动态路由-配置 文章目录 目录 系列文档目…

【Redis】背景知识

一、Redis的特性 Redis是一种基于键值对&#xff08;key-value&#xff09;的NoSQL数据库&#xff0c;与很多键值对数据库不同的是&#xff0c;Redis中的值可以是由string&#xff08;字符串&#xff09;&#xff0c;hash&#xff08;哈希&#xff09;&#xff0c;list&#xf…

航电系统的任务载荷集成技术要点概述!

一、任务载荷集成技术难点 1. 接口标准化与兼容性 异构设备协议冲突&#xff1a;不同厂商的载荷设备&#xff08;如光学相机、雷达、电子战模块&#xff09;采用不同的通信协议&#xff08;如1553B、RS422、以太网&#xff09;&#xff0c;需设计统一的总线接口标准以支持即…

OceanBase V4.3.5 上线全文索引功能,让数据检索更高效

近日&#xff0c;OceanBase 4.3.5 BP1 版本正式推出了企业级全文索引功能。该版本在中文分词、查询效率及混合检索能力上进行了全面提升。经过自然语言模式和布尔模式在不同场景下的对比测试&#xff0c;OceanBase 的全文索引性能明显优于 MySQL。 点击下载 OceanBase 社区版…

Qt中的信号与槽及其自定义

信号源&#xff1a;哪个控件发的信号 信号的类型&#xff1a;用户进行不同的操作就会触发不同的信号 如点击按钮&#xff0c;在输入框移动光标&#xff0c;勾选一个复选框&#xff0c;选 择一个下拉框 信号的处理方式&#xff1a;槽(slot)----也就是函数&#xff0c;Qt中用con…

【PFPGA学习】状态机思想编程HDLbitsFPGA练习

目录 一、用状态机实现LED流水灯 1.1状态机思想 1.2状态机思想LED流水灯 1.3 modesim仿真 1.4 FPGA烧录实现 二、CPLD和FPGA芯片 1. 核心结构与技术原理 2. 性能与容量 3. 适用场景 &#xff14;. 选型建议 三、HDLbitsFPGA练习记录&#xff08;combinational logic…

Android 中集成 Unity 工程的步骤

在 Adroid 项目中集成 Unity 工程,主要步骤如下: 一、前提条件 1、已有一个 Android 工程项目; 2、Unity 工程已导出为 Android 工程,目录大概如下: 二、集成步骤 1、在 Android 工程中导入 Unity 工程的 unityLibrary 模块。 在 Android Studio 中,点击菜单栏 Fil…

Python从入门到精通全套视频教程免费

概述 &#x1f4e2; 所有想学Python的小伙伴看过来&#xff01;作为深耕编程领域的技术分享者&#xff0c;最新整理了一份Python从0到1的视频教程。 &#x1f4a1;亮点 ✅ 保姆级系统路线&#xff1a;从环境搭建、语法精讲&#xff0c;到爬虫/数据分析/AI/Web全栈开发&#…

蓝桥杯:对字符串处理常用知识笔记

一、前面四个是计算带有空格字符串的的长度计算 C语言代码 #include<string.h> #include<stdio.h> int main() { char s[105]; gets(s); printf("%d", strlen(s)); return 0; } 算法2 C 代码&#xff08;常用&#xff09; #include <iostream> #in…

实现一个 Markdown 编辑器组件:Vue 3 + Vite + Highlight.js

文章目录 一、项目背景与需求分析二、搭建基础项目1. 初始化 Vue 3 项目2. 安装依赖 三、实现 Markdown 编辑器组件1. 创建 Markdown 编辑器组件2. 组件说明 四、优化与拓展1. 自动保存功能2. 文件上传功能 五、总结 一、项目背景与需求分析 在现代前端开发中&#xff0c;Mark…

帆软fvs文件中某表格新增数据来声提醒

1.上传音频文件到帆软安装目录的指定环境 准备一个音频文件&#xff08;如 mp3 格式&#xff09;&#xff0c;并将其放置在合适的目录。 例如&#xff1a;%FR_HOME%\webapps\webroot\help 2.点击 FVS 模板左上角「模板>页面加载结束事件」&#xff0c;输入以下 JavaScript …

从零用java实现 小红书 springboot vue uniapp (11)集成AI聊天机器人

前言 移动端演示 http://8.146.211.120:8081/#/ 管理端演示 http://8.146.211.120:8088/#/ 项目整体介绍及演示 前面的文章我们主要完成了基础模块的开发 这次我们跟一下热点 创建AI聊天机器人 并嵌入到我们的uniapp中 首先需要了解dify我已经完成了搭建win10 VMware安装ubuntu…