# fox-ioc-framework **Repository Path**: dongchenglin/fox-ioc-framework ## Basic Information - **Project Name**: fox-ioc-framework - **Description**: Java古法编程系列:手写IOC - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-06 - **Last Updated**: 2026-05-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 🔥 Fox IoC Framework > 从零实现 IoC 容器,彻底砸碎 Spring 的底层黑盒 > > 《Java 古法编程》系列第一篇 [](https://gitee.com/dongchenglin/fox-ioc-framework/stargazers) [](https://gitee.com/dongchenglin/fox-ioc-framework/members) [](LICENSE) --- ## 📖 项目介绍 ### 痛点 在 AI 辅助编程工具日益成熟的今天,许多 Java 开发者陷入了一种困惑: - 日常频繁使用 `@RestController` 和 `@Autowired` - 对 Spring 框架的内部运行机制知之甚少 - 被问到"如果没有 Spring,你如何组织复杂的对象依赖关系"时哑口无言 ### 解决方案 本项目带你**手撕 IoC 容器**,不依赖任何第三方库,用纯 Java SE API 从零实现: - 📦 **包扫描**:运行时发现所有组件 - 🔨 **反射实例化**:动态创建 Bean 对象 - 💉 **依赖注入**:自动装配 Bean 之间的依赖 - 🔄 **循环依赖处理**:理解 Spring 三级缓存的设计哲学 --- ## 🏗️ 核心架构 ``` ┌─────────────────────────────────────────────────────────────────┐ │ FoxApplicationContext │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 阶段一:scanPackageRecursively() │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ java.class.path → 遍历 classpath │ │ │ │ 递归扫描目录 → Class.forName() → @FoxBean 判断 │ │ │ │ → beanDefinitionMap │ │ │ └─────────────────────────────────────────────────────────┘ │ │ ↓ │ │ 阶段二:instantiateBeans() │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Constructor.newInstance() → 创建"空壳"实例 │ │ │ │ → singletonObjects (提前暴露,解决循环依赖) │ │ │ └─────────────────────────────────────────────────────────┘ │ │ ↓ │ │ 阶段三:populateBeans() │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ getDeclaredFields() → @FoxInject 判断 │ │ │ │ field.setAccessible(true) → field.set() │ │ │ │ → 依赖装配完成 │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## 🚀 快速开始 ### 环境要求 - JDK 11+ - Maven 3.6+ ### 编译运行 ```bash # 克隆项目 git clone https://gitee.com/dongchenglin/fox-ioc-framework.git cd fox-ioc-framework # 编译 mvn clean compile # 运行 Demo mvn exec:java -Dexec.mainClass="com.fox.test.MainApplication" ``` ### 运行结果 ``` ╔══════════════════════════════════════════════════╗ ║ Fox IoC 容器 - 古法编程系列 Demo ║ ╚══════════════════════════════════════════════════╝ [Fox-IoC] 阶段一:开始包扫描... [Fox-IoC] 发现 Bean: userService (com.fox.test.service.UserService) [Fox-IoC] 发现 Bean: orderService (com.fox.test.service.OrderService) [Fox-IoC] 发现 Bean: emailService (com.fox.test.service.EmailService) [Fox-IoC] 发现 Bean: userDao (com.fox.test.dao.UserDao) [Fox-IoC] 包扫描完成,发现 4 个 Bean 定义 [Fox-IoC] 阶段二:开始实例化 Bean... [Fox-IoC] Bean 实例化: userService -> UserService [Fox-IoC] Bean 实例化: orderService -> OrderService ... [Fox-IoC] 阶段三:开始依赖注入... [Fox-IoC] 依赖注入: userService.orderService -> orderService [Fox-IoC] 依赖注入完成 ═══════════════════════════════════════════════════ 容器初始化完成,开始使用 Bean ═══════════════════════════════════════════════════ UserService 执行中... OrderService 处理中... ``` --- ## 📚 核心技术解析 ### 1. 包扫描:`ClassLoader.getResource()` 的正确打开方式 ```java // 传统方式:ClassLoader.getResource() 在 IDE 环境下可能返回 null URL resource = classLoader.getResource(resourcePath); // 正确方式:直接遍历 classpath String classpath = System.getProperty("java.class.path"); String[] paths = classpath.split(System.getProperty("path.separator")); for (String path : paths) { File packageDir = new File(path, resourcePath); if (packageDir.exists()) { doScan(packageDir, basePackage); } } ``` ### 2. 反射实例化:构造函数选择 ```java // ⚠️ JDK 9+ 已废弃 Object obj = clazz.newInstance(); // ✅ 推荐方式 Object obj = clazz.getDeclaredConstructor().newInstance(); ``` ### 3. 依赖注入:绕过访问控制 ```java // 获取类的所有字段(包括 private) Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(FoxInject.class)) { // 绕过访问控制检查 field.setAccessible(true); // 注入依赖 field.set(instance, dependency); } } ``` ### 4. 循环依赖的解决之道 ``` 问:为什么 Spring 要把"实例化"和"注入"分开? 答:为了解决循环依赖! UserService → OrderService → UserService (无限递归!) Spring 的解决方案:提前暴露引用 1. 先创建"空壳"实例 → 存入 singletonObjects 2. 再执行依赖注入 3. 即使是循环依赖,也能获得对方的引用 ``` --- ## 📁 项目结构 ``` fox-ioc-framework/ ├── pom.xml ├── LICENSE # MIT 开源协议 │ └── src/ └── main/java/ └── com/fox/ ├── ancient/framework/ # 🔥 框架核心 │ ├── annotation/ │ │ ├── FoxBean.java # Bean 标记注解 │ │ └── FoxInject.java # 依赖注入注解 │ └── context/ │ └── FoxApplicationContext.java # 核心容器 │ └── test/ # 测试代码 ├── MainApplication.java ├── service/ │ ├── UserService.java │ ├── OrderService.java │ └── EmailService.java └── dao/ └── UserDao.java ``` --- ## 🧪 单元测试 ```bash mvn test ``` 测试覆盖: - ✅ Bean 注册与获取 - ✅ 按类型获取 Bean - ✅ 依赖注入成功性 - ✅ Bean 名称列表 --- ## 🎓 延伸学习 ### 本系列其他文章 | 篇目 | 主题 | 状态 | | ------ | ----------------------- | ----------- | | 第一篇 | IoC 容器原理与实现 | ✅ 已完成 | | 第二篇 | 动态代理与 AOP 底层原理 | 🔜 敬请期待 | | 第三篇 | 手写 MyBatis ORM 框架 | 🔜 敬请期待 | ### 深入学习路线 ``` Java 基础 ↓ 反射机制(java.lang.reflect) ↓ 类加载器(ClassLoader) ↓ IoC / DI 容器 ↓ 动态代理(Proxy / ASM) ↓ AOP 面向切面编程 ↓ 字节码插桩(Javassist / ByteBuddy) ↓ JIT / AOT 编译原理 ``` --- ## 👤 关于作者