当前位置: 首页 > news >正文

实现自己的IOC容器——Winter (一)Bean加载

做了几年 Java 开发每天和 Spring系列框架打交道。虽然各种注解、中间件用的飞起但说实话心里挺虚的。框架帮我们屏蔽了太多细节舒服是舒服了可久而久之感觉自己像个被惯坏的孩子——离了脚手架就不会盖房了。为了治好这份“技术焦虑症”也为了满足那点该死的好奇心我决定自己动手从零开始撸一个简易版的 Spring 容器。不求功能强大只求把那些神秘的面纱亲手揭开。项目地址https://gitee.com/sheevg/winter目前还在持续更新中....我是从《Spring源码深度解析第二版》这本书开始了解Spring框架所以Winter容器也是从解析Xml配置实现Bean注册后面会陆续更新注解驱动、AOP等等。一、解析Xml配置、注册BeanDefinition参考方法XmlBeanDefinitionReader.loadBeanDefinitions(resource)Winter容器是Xml配置文件驱动对配置的解析流程如下1. 加载xml文件成Resource对象2. 将Resource转成Document解析Document将Bean的配置解析成BeanDefinition3. 将解析完成的BeanDefinition放入容器WinterBeanFactory中1. 加载xml文件转成Document对象定义ClassPathResource作为类路径下文件抽象定义getInputStream方法用于读取。定义ResourceLoader用于统一加载文件。import java.io.FileNotFoundException; import java.io.InputStream; /** * 用于解析 classpath 路径下的文件 */ public class ClassPathResource implements Resource{ // 文件路径 private final String path; // 用于加载文件的 private final ClassLoader classLoader; public ClassPathResource(String path){ this(path,null); } public ClassPathResource(String path,ClassLoader classLoader){ // classloader加载时不能以/ 为开头比如/config/xx.xml if(path.startsWith(/)){ path path.substring(1); } this.path path; this.classLoader classLoader ! null ? classLoader : ClassLoader.getSystemClassLoader() ; } Override public InputStream getInputStream() throws FileNotFoundException { InputStream inputStream this.classLoader.getResourceAsStream(this.path); if(inputStream null){ throw new FileNotFoundException(描述: 类路径下的资源 [ this.path ] 不存在无法打开); } return inputStream; } }2. 解析Document成BeanDefintion定义BeanDefinitionReader用于将Resource的输入流转成Document对象使用dom4j转换。public int loadBeanDefinition(Resource resource) throws FileNotFoundException, DocumentException { // 获取输入流 InputStream is resource.getInputStream(); SAXReader reader new SAXReader(); // 将输入流转成 document Document document reader.read(is); // 计算注册了多少 int countBefore beanDefinitionRegistry.getBeanDefinitionCount(); doRegisterBeanDefinition(document.getRootElement()); return beanDefinitionRegistry.getBeanDefinitionCount() - countBefore; }在doRegisterBeanDefinition方法中遍历bean element在用解析配置的委托类BeanDefinitionParserDelegate进行具体解析。最终将bean配置解析为BeanDefinition对象。public void doRegisterBeanDefinition(Element rootElement){ System.out.println(rootElement.getName()); BeanDefinitionParserDelegate parserDelegate new BeanDefinitionParserDelegate(); // 获取所有 bean标签 ListElement beanElements rootElement.elements(bean); beanElements.forEach(e - { BeanDefinitionHolder bdHolder parserDelegate.parseBeanDefinition(e); beanDefinitionRegistry.registerBeanDefinition(bdHolder.getBeanName(),bdHolder.getBeanDefinition()); }); }public BeanDefinitionHolder parseBeanDefinition(Element element) { String id element.attributeValue(id); String className element.attributeValue(class); String initMethod element.attributeValue(init-method); // 构造函数 ListConstructorArg argList new ArrayList(); ListElement constructorArgs element.elements(constructor-arg); for(int i0; iconstructorArgs.size();i){ Element constructorArg constructorArgs.get(i); String argName constructorArg.attributeValue(name); String ref constructorArg.attributeValue(ref); String value constructorArg.attributeValue(value); ConstructorArg ca ConstructorArg.builder() .index(i) .name(argName) .type(StringUtils.isNotBlank(ref)?ConstructorArgEnum.REF:ConstructorArgEnum.VALUE) .value(StringUtils.isNotBlank(ref)?ref:value) .build(); argList.add(ca); } BeanDefinition bd BeanDefinition.builder() .id(id) .beanName(id) .className(className) .initMethodName(initMethod) .argList(argList) // 默认单例 .isSingleton(true) .build(); return new BeanDefinitionHolder(id,bd); }3. 注册BeanDefinition需要在WinterBeanFactory中创建一个本地缓存ConcurrentHashMap将创建好的BeanDefinition放进去即可。private final MapString, BeanDefinition beanDefinitionMap new ConcurrentHashMap(64); Override public void registerBeanDefinition(String beanName, BeanDefinition bd) { this.beanDefinitionMap.put(beanName,bd); }明天更新如何将配置中的Bean注册进容器....
http://www.rkmt.cn/news/1393572.html

相关文章:

  • 爆款标题生成率提升4.8倍!广告公司总监压箱底的ChatGPT创意写作AB测试报告(2024Q2最新)
  • 百度网盘下载加速终极指南:使用Python工具实现满速下载的完整教程
  • 系统辨识选最小二乘还是最大似然?一个传感器噪声的例子讲明白
  • 从“飞起来”到“管得好”:2026工程进度低空管理系统供应商推荐 - 品牌2025
  • ChatGPT账号被临时限制?官方未公开的4级风控触发阈值(含IP信誉分、会话熵值、UA指纹校验逻辑)
  • 鸿蒙数学108篇 第四篇:存在与虚无数理逻辑:数学存在的底层公理
  • Scrum成功案例分析
  • 虚拟网络映射优化:基于时间概率模型的动态资源调度
  • 降精度计算在射电天文成像中的应用:FPGA硬件加速实践
  • Linux 文件权限详解:chmod、chown、umask 到底怎么用?
  • 嵌入式SIR可调谐腔体滤波器设计:实现52.4%宽调谐与恒定带宽
  • SSH Kex_exchange_identification错误根因与实战修复指南
  • 2026年5月欧米茄“非官方售后”陷阱深度起底报告 - 资讯纵览
  • HarmonyOS ArkTS DeviceUtil 设备标识符完整指南:DeviceId、ODID、OAID、AAID
  • 解决Claude Code token不足与封号风险Taotoken提供稳定替代方案
  • 【SSD】闪存2 闪存芯片架构
  • 如何快速上手Kohya_SS:专业AI绘画模型训练完全指南
  • 3个步骤让Windows系统运行如飞:Win11Debloat系统优化指南
  • 如何快速清理Windows 11:Win11Debloat系统优化完全指南
  • 【ACM出版、过往最快4.5个月检索】第二届人机交互与机器学习国际学术会议(HCIML 2026) - 每天学术做一点
  • 旺哥黄金回收(连锁品牌)|2026年5月绵阳黄金回收价格行情+连锁品牌优势+避坑指南+真实案例(涪城/游仙/高新/经开/科创园/安州通用) - 润富黄金珠宝行
  • LFDP算法解析:局部特征判别投影的原理、实现与调优
  • AI开发工具实战:二、Superpowers 工作流——让你的 AI 编码助手开挂
  • 手机相机拍的图片提取WGS84经纬度,调研图片EXIF信息
  • 3分钟掌握Win11优化:一键清理让电脑重获新生
  • Java算法练习day3
  • CAD子系统,是自研还是外包?
  • 2026年5月冷制皂代工厂对比:基于重资产合规矩阵与品牌资产化的深度权威研报 - 资讯焦点
  • 终极指南:如何快速解决Windows热键冲突的完整方案
  • 【C++】数据结构之哈希表(散列表)