45 | 工厂模式(下):如何设计实现一个Dependency Injection框架?
王争
该思维导图由 AI 生成,仅供参考
在上一节课我们讲到,当创建对象是一个“大工程”的时候,我们一般会选择使用工厂模式,来封装对象复杂的创建过程,将对象的创建和使用分离,让代码更加清晰。那何为“大工程”呢?上一节课中我们讲了两种情况,一种是创建过程涉及复杂的 if-else 分支判断,另一种是对象创建需要组装多个其他类对象或者需要复杂的初始化过程。
今天,我们再来讲一个创建对象的“大工程”,依赖注入框架,或者叫依赖注入容器(Dependency Injection Container),简称 DI 容器。在今天的讲解中,我会带你一块搞清楚这样几个问题:DI 容器跟我们讲的工厂模式又有何区别和联系?DI 容器的核心功能有哪些,以及如何实现一个简单的 DI 容器?
话不多说,让我们正式开始今天的学习吧!
工厂模式和 DI 容器有何区别?
实际上,DI 容器底层最基本的设计思路就是基于工厂模式的。DI 容器相当于一个大的工厂类,负责在程序启动的时候,根据配置(要创建哪些类对象,每个类对象的创建需要依赖哪些其他类对象)事先创建好对象。当应用程序需要使用某个类对象的时候,直接从容器中获取即可。正是因为它持有一堆对象,所以这个框架才被称为“容器”。
DI 容器相对于我们上节课讲的工厂模式的例子来说,它处理的是更大的对象创建工程。上节课讲的工厂模式中,一个工厂类只负责某个类对象或者某一组相关类对象(继承自同一抽象类或者接口的子类)的创建,而 DI 容器负责的是整个应用中所有类对象的创建。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文深入介绍了依赖注入(DI)容器的设计原理和实现方法。首先对比了工厂模式和DI容器的区别,指出DI容器是一个大的工厂类,负责整个应用中所有类对象的创建,包括配置解析、对象创建和对象生命周期管理。其次详细介绍了DI容器的核心功能,包括配置解析、对象创建和对象生命周期管理。最后提出了实现一个简单的DI容器的方法,包括最小原型设计、提供执行入口和配置文件解析。通过示例代码展示了DI容器的使用方式和执行入口的设计。文章重点讲解了BeansFactory类中的createBean()函数,以及可能出现的循环依赖问题,并提出了解决方案。整体而言,本文对于想要了解DI容器的读者具有很高的参考价值,尤其适合对底层原理感兴趣的读者。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《设计模式之美》,新⼈⾸单¥98
《设计模式之美》,新⼈⾸单¥98
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(81)
- 最新
- 精选
- 郑大钱“初级工程师在维护代码,高级工程师在设计代码,资深工程师在重构代码” 依赖注入框架好牛逼呀!当手把手教我设计一个框架之后,才破除了我对框架的权威和迷信。 自己最开始做业务也是在原有框架上面修修补补,回过头来看,发现自己非常能忍,即使原有的框架很难用,自己也能坚持用下去。 转念一想,那不是能忍,那是懒。懒得去理解框架的原理,懒得让它更易用。 像豌豆公主一样保持自己的敏感,是持续改进的动力。
作者回复: 说的好
2020-11-1719 - 少年锦时beanDefinition.isLazyInit() == false 为什么不直接写成!beanDefinition.isLazyInit() 呢
作者回复: 也可以~
2020-07-04 - 沈康默默的掏出了《spring源码深度解析》回顾一番 1、构造器循环依赖 构造器注入的循环依赖是无法解决的,只能抛出bean创建异常使容器无法启动 如何判断是循环依赖? 把正在创建的bean放入到一个(正在创建的map)中,如果依赖创建bean在此map中存在,则抛出异常。 2、setter方法循环依赖 ①单例情况可以解决循环依赖,方法是提前暴露一个返回该单例的工厂方法,让依赖对象可以引用到 ②多例不能解决循环依赖,因为多例不需要缓存2020-02-187163
- undefined把本文的示例补全成了可执行代码: https://github.com/plusmancn/learn-java/tree/master/src/main/java/Exercise/di 顺便纠正一个笔误: BeansFactory 下 createBean 方法中:singletonObjects.contains 应为 singletonObjects. containsKey2020-02-23264
- javaadu20200218再次复习: 1. 研究了Spring容器中处理循环依赖的知识点:(1)只能处理单例的、setter注入的循环依赖,其他的注入模式无法处理;(2)依赖缓存处理循环依赖,关键思想是,将正在创建中的对象提前暴露一个单例工厂,让其他实例可以引用到 2. 网上一篇比较好的文章:https://juejin.im/post/5d0d8f64f265da1b7b3193ac2020-02-19238
- 简单猫不要被这些所谓的专业化名词吓到了 什么三级缓存。a依赖b,b依赖c,c依赖a,d依赖a,b,c什么的,你要解决的核心是不要重复创建。那么你就要把已经创建的对象存起来(map,hashmaps什么的) ,然后再次创建的时候先去缓存map中读取,没有才创建。 创建对象流程:1先反射创建类对象 2然后配置类里面的属性 方法(依赖就在这)。 至于你要怎么利用设计模式解耦 分3级缓存 分别存储完全实例化的对象 未设置属性方法类对象 还是对象工厂 那就看如何好用咯2020-05-14337
- 此鱼不得水Spring解决循环依赖的办法是多级缓存。2020-02-1423
- zhengyu.nie基本就是Spring源码大体原型了,委托的BeanFactory在Spring源码里是DefaultListableBeanFactory。循环依赖解决是三级缓存,提前暴露还没有初始化结束的bean。检测是Map存一下过程,aba这样顺序判断,有重复(a出现两次)就是环了。 三级缓存源码对应 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton /** * Return the (raw) singleton object registered under the given name. * <p>Checks already instantiated singletons and also allows for an early * reference to a currently created singleton (resolving a circular reference). * @param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */ @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; } /** Cache of singleton objects: bean name to bean instance. */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);2020-04-2415
- 王先森php开发者默默的去瞅laravel的DI容器2020-06-1611
- 好吃不贵createBean先用Topology sort看是否有环,然后再按序创建?2020-02-1419
收起评论