深入解析 Spring IOC AOP:原理、源码与实战

深入解析 Spring IOC & AOP:原理、源码与实战

Spring 框架的核心在于 IOC(控制反转)AOP(面向切面编程)。今天,我们将深入剖析它们的原理,结合源码解析,并通过 Java 代码实战来掌握这两个核心概念。


📌 1. 什么是 IOC(控制反转)?

IOC(Inversion of Control)是 Spring 的核心思想,它将对象的创建和依赖关系的管理交给 Spring 容器,避免了传统的 new 关键字实例化方式。

🔥 1.1 IOC 机制

Spring 使用 BeanFactoryApplicationContext 管理 Bean 的生命周期,主要流程如下:

  1. 读取配置(XML 或注解)
  2. 实例化 Bean(通过 BeanFactory
  3. 依赖注入(通过 @Autowired
  4. Bean 生命周期管理

📌 2. 手写简易 IOC 容器

我们用 Java 代码手写一个简化版的 IOC 容器,模拟 Spring 依赖注入的实现。

📝 代码示例:

import java.util.HashMap;
import java.util.Map;// 模拟 Spring 容器
class SimpleIOC {private Map<String, Object> beanContainer = new HashMap<>();// 注册 Beanpublic void registerBean(String name, Object obj) {beanContainer.put(name, obj);}// 获取 Beanpublic Object getBean(String name) {return beanContainer.get(name);}
}// 测试 IOC 容器
class UserService {public void sayHello() {System.out.println("Hello, Spring IOC!");}
}public class TestIOC {public static void main(String[] args) {SimpleIOC ioc = new SimpleIOC();ioc.registerBean("userService", new UserService());UserService userService = (UserService) ioc.getBean("userService");userService.sayHello();}
}

🔍 运行结果

Hello, Spring IOC!

分析

  • SimpleIOC 充当 Spring 容器,存储和管理 Bean 实例。
  • registerBean() 方法模拟 ApplicationContext 注册 Bean 的功能。
  • getBean() 方法模拟 getBean(Class<T> clazz) 获取对象。

📌 3. 什么是 AOP(面向切面编程)?

AOP(Aspect-Oriented Programming)通过 动态代理 在方法执行前后加入额外逻辑,常用于 日志、事务、权限控制 等场景。

🔥 3.1 AOP 机制

Spring AOP 主要通过 JDK 动态代理(基于接口)和 CGLIB(基于子类)实现。

📖 3.2 Spring AOP 代理模式

Spring AOP 主要使用 代理模式,在目标方法执行前后执行增强逻辑,如:

  • @Before(前置通知)
  • @AfterReturning(后置通知)
  • @Around(环绕通知)

📌 4. 手写 AOP 代理(JDK 动态代理)

我们使用 JDK 动态代理 实现 AOP,模拟 Spring @Transactional 事务管理。

📝 代码示例:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 业务接口
interface UserService {void createUser();
}// 业务实现类
class UserServiceImpl implements UserService {public void createUser() {System.out.println("创建用户...");}
}// AOP 代理类
class AOPProxy implements InvocationHandler {private Object target;public AOPProxy(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("开启事务...");Object result = method.invoke(target, args);System.out.println("提交事务...");return result;}// 生成代理对象public static Object getProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new AOPProxy(target));}
}// 测试 AOP 代理
public class TestAOP {public static void main(String[] args) {UserService userService = new UserServiceImpl();UserService proxyService = (UserService) AOPProxy.getProxy(userService);proxyService.createUser();}
}

🔍 运行结果

开启事务...
创建用户...
提交事务...

分析

  • AOPProxy 通过 JDK 动态代理 在方法调用前后加入事务逻辑。
  • getProxy() 生成代理对象,并拦截 UserService 的方法调用。
  • 运行后,createUser() 方法被代理增强,实现 AOP 事务管理功能。

📌 5. Spring AOP 实战(@Aspect)

在 Spring 中,我们可以使用 @Aspect@Around 注解实现 AOP 事务管理。

📝 代码示例:

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Aspect
@Component
public class TransactionAspect {@Before("execution(* com.service.*.*(..))")public void beginTransaction() {System.out.println("开启事务...");}@After("execution(* com.service.*.*(..))")public void commitTransaction() {System.out.println("提交事务...");}
}

🌟 关键点

  • @Aspect:声明 AOP 切面类
  • @Before / @After:在方法执行前/后执行事务逻辑
  • execution(* com.service.*.*(..)):匹配 com.service 包下的所有方法

📌 6. 总结

功能Spring 机制手写代码
IOC依赖注入(DI)手写 BeanFactory
AOP事务管理、日志JDK 动态代理
Spring AOP@Aspect 切面@Before@After

今日收获

  • 理解了 IOC 机制,并手写 IOC 容器
  • 掌握了 AOP 代理机制,并手写 JDK 动态代理
  • 结合 Spring @Aspect 注解,掌握 AOP 事务管理

🚀 明日预告:Spring MVC 深度解析(DispatcherServlet、HandlerMapping、拦截器)

🔗 学习资料
📖 Spring 官方文档


💬 你对 Spring IOC & AOP 有什么疑问?欢迎留言交流! 🚀

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

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

相关文章

LLM之RAG理论(十四)| RAG 最佳实践

RAG 的过程很复杂&#xff0c;包含许多组成部分。我们如何确定现有的 RAG 方法及其最佳组合&#xff0c;以确定最佳 RAG 实践&#xff1f; 论文 《Searching for Best Practices in Retrieval-Augmented Generation》给出了回答。 本文将从以下三方面进行介绍&#xff1a; 首先…

利用knn算法实现手写数字分类

利用knn算法实现手写数字分类 1.作者介绍2.KNN算法2.1KNN&#xff08;K-Nearest Neighbors&#xff09;算法核心思想2.2KNN算法的工作流程2.3优缺点2.4 KNN算法图示介绍 3.实验过程3.1安装所需库3.2 MNIST数据集3.3 导入手写数字图像进行分类3.4 完整代码3.5 实验结果 1.作者介…

C语言-适配器模式详解与实践

文章目录 C语言适配器模式详解与实践1. 什么是适配器模式&#xff1f;2. 为什么需要适配器模式&#xff1f;3. 实际应用场景4. 代码实现4.1 UML 关系图4.2 头文件 (sensor_adapter.h)4.3 实现文件 (sensor_adapter.c)4.4 使用示例 (main.c) 5. 代码分析5.1 关键设计点5.2 实现特…

Rust函数、条件语句、循环

文章目录 函数**语句与表达式**条件语句循环 函数 Rust的函数基本形式是这样的 fn a_func(a: i32) -> i32 {}函数名是蛇形风格&#xff0c;rust不在意函数的声明顺序&#xff0c;只需要有声明即可 函数参数必须声明参数名称和类型 语句与表达式 这是rust非常重要的基础…

maptalks图层交互 - 模拟 Tooltip

maptalks图层交互 - 模拟 Tooltip 图层交互-模拟tooltip官方文档 <!DOCTYPE html> <html><meta charsetUTF-8 /><meta nameviewport contentwidthdevice-width, initial-scale1 /><title>图层交互 - 模拟 Tooltip</title><style typet…

好吧好吧,看一下达梦的模式与用户的关系

单凭个人感觉&#xff0c;模式在达梦中属于逻辑对象合集&#xff0c;回头再看资料 应该是一个用户可以对应多个模式 问题来了&#xff0c;模式的ID和用户的ID一样吗&#xff1f; 不一样 SELECT USER_ID,USERNAME FROM DBA_USERS WHERE USERNAMETEST1; SELECT ID AS SCHID, NA…

python socket模块学习记录

python黑马程序员 通过python内置socket模块&#xff0c;在电脑本地开发一个服务器&#xff0c;一个客户端&#xff0c;连接后进行连续的聊天。服务器和客户端均可输入exit&#xff0c;主动退出连接。 服务器开发.py import socket# 创建Socket对象 socket_server socket.s…

7-2 sdut-C语言实验-逆序建立链表

7-2 sdut-C语言实验-逆序建立链表 分数 20 全屏浏览 切换布局 作者 马新娟 单位 山东理工大学 输入整数个数N&#xff0c;再输入N个整数&#xff0c;按照这些整数输入的相反顺序建立单链表&#xff0c;并依次遍历输出单链表的数据。 输入格式: 第一行输入整数N;&#xff…

针对永磁电机(PMM)的d轴和q轴电流,考虑交叉耦合补偿,设计P1控制器并推导出相应的传递函数

电流控制回路:针对永磁电机(PMM)的d轴和q轴电流&#xff0c;考虑交叉耦合补偿&#xff0c;设计P1控制器并推导出相应的传递函数。 1. 永磁电机&#xff08;PMM&#xff09;的数学模型 在同步旋转坐标系&#xff08; d − q d - q d−q 坐标系&#xff09;下&#xff0c;永磁同…

ROS多机通信(四)——Ubuntu 网卡 Mesh 模式配置指南

引言 使用Ad-hoc加路由协议和直接Mesh模式配置网卡实现的网络结构是一样的&#xff0c;主要是看应用选择&#xff0c; Ad-Hoc模式 B.A.T.M.A.N. / OLSR 优点&#xff1a;灵活性高&#xff0c;适合移动性强或需要优化的复杂网络。 缺点&#xff1a;配置复杂&#xff0c;需手动…

chap1:统计学习方法概论

第1章 统计学习方法概论 文章目录 第1章 统计学习方法概论前言章节目录导读 实现统计学习方法的步骤统计学习分类基本分类监督学习无监督学习强化学习 按模型分类概率模型与非概率模型 按算法分类按技巧分类贝叶斯学习核方法 统计学习方法三要素模型模型是什么? 策略损失函数与…

爬虫案例-爬取某站视频

文章目录 1、下载FFmpeg2、爬取代码3、效果图 1、下载FFmpeg FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。 点击下载: ffmpeg 安装并配置 FFmpeg 步骤&#xff1a; 1.下载 FFmpeg&#xff1a; 2.访问 FFmpeg 官网。 3.选择 Wi…

车载以太网网络测试-22【传输层-DOIP协议-5】

目录 1 摘要2 DoIP时间参数2.1 ISO 13400定义的时间参数2.2 参数示例 3 DoIP节点内部状态机4 UDSonIP概述5 总结 1 摘要 本文继续对DOIP协议进行介绍&#xff0c;主要是DOIP相关的时间参数、时间参数定义以及流程示例。推荐大家对上文专题进行回顾&#xff0c;有利于系统性学习…

(论文总结)思维链激发LLM推理能力

研究背景&动机 背景:扩大模型规模已被证实具有提升模型性能和模型效率的功效&#xff0c;但是LLM对于完成推理、算术任务仍有较大不足。 动机:从之前的应用和研究中得知&#xff0c;可以用生成自然语言解释、使用神经符号等形式语言的方法来提高大模型的算术推理能力&…

前后端开发概述:架构、技术栈与未来趋势

一、前后端开发的基本概念 1.1 什么是前后端开发&#xff1f; 前后端开发是 Web 开发的两个核心部分&#xff0c;各自承担不同的职责&#xff1a; 前端&#xff08;Frontend&#xff09; 负责网页的用户界面&#xff08;UI&#xff09;和用户体验&#xff08;UX&#xff09;…

anythingLLM结合searXNG实现联网搜索

1、docker-compose 部署searXNG GitHub - searxng/searxng-docker: The docker-compose files for setting up a SearXNG instance with docker. cd /usr/local git clone https://github.com/searxng/searxng-docker.git cd searxng-docker 2、修改 .env文件 # By default…

人形机器人科普

人形机器人&#xff08;Humanoid Robot&#xff09;是一种模仿人类外形和行为的机器人&#xff0c;通常具有头部、躯干、双臂和双腿等结构。它们的设计目标是与人类环境无缝交互&#xff0c;执行复杂的任务&#xff0c;甚至在某些领域替代人类工作。 1. 人形机器人的定义与特点…

【CICD】Ansible知识库

一、主机清单配置 1. 配置文件路径 默认路径 /etc/ansible/hosts 这是 Ansible 的全局默认库存文件路径&#xff0c;但许多用户可能不会直接使用它。项目目录或自定义路径 用户通常会为不同项目创建独立的库存文件&#xff0c;例如&#xff1a; 当前目录下的 hosts、inventor…

ArkUI-List组件

列表是一个复杂的容器&#xff0c;当列表项达到一定数量&#xff0c;使得列表内容超出其范围的时候&#xff0c;就会自动变为可以滚动。列表适合用来展现同类数据类型。 List的基本使用方法 List组件的构建声明是这个样子的 List(value?: {space?:number | string, initial…

Ubuntu实时读取音乐软件的音频流

文章目录 一. 前言二. 开发环境三. 具体操作四. 实际效果 一. 前言 起因是这样的&#xff0c;我需要在Ubuntu中&#xff0c;实时读取正在播放音乐的音频流&#xff0c;然后对音频进行相关的处理。本来打算使用的PipewireHelvum的方式实现&#xff0c;好处是可以直接利用Helvum…