手把手带你写一个 MiniSpring
郭屹
前 Sun Microsystems Java 研发工程师,开源软件 MiniSpring、MiniTomcat 开发者
6170 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 26 讲
手把手带你写一个 MiniSpring
15
15
1.0x
00:00/00:00
登录|注册

04|增强IoC容器:如何让我们的Spring支持注解?

你好,我是郭屹。
上节课我们通过一系列的操作使 XML 使配置文件生效,然后实现了 Spring 中 Bean 的构造器注入与 setter 注入,通过引入“早期毛胚 Bean”的概念解决了循环依赖的问题,我们还为容器增加了 Spring 中的一个核心方法 refresh(),作为整个容器启动的入口。现在我们的容器已经初具模型了,那如何让它变得更强大,从种子长成一株幼苗呢?
这节课我们就来实现一个增强版的 IoC 容器,支持通过注解的方式进行依赖注入。注解是我们在编程中常用的技术,可以减少配置文件的内容,便于管理的同时还能提高开发效率。所以这节课我们将实现 Autowired 注解,并用这个方式进行依赖注入

目录结构

我们手写 MiniSpring 的目的是更好地学习 Spring。因此,我们会时不时回头来整理整个项目的目录结构,和 Spring 保持一致。
现在我们先参考 Spring 框架的结构,来调整我们的项目结构,在 beans 目录下新增 factory 目录,factory 目录中则新增 xml、support、config 与 annotation 四个目录。
├── beans
│ └── factory
│ ├── xml
│ └── support
│ └── config
│ └── annotation
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文详细介绍了如何通过增强IoC容器,实现对注解的支持,从而实现依赖注入。作者首先调整了项目目录结构,使其更加清晰,然后详细讲解了如何实现Autowired注解,并利用BeanPostProcessor接口在Bean初始化前后进行处理,以实现依赖注入。通过定义Autowired注解和处理类AutowiredAnnotationBeanPostProcessor,作者展示了如何利用反射获取标注了Autowired注解的成员变量,并将其初始化成一个Bean,然后注入属性,从而实现依赖注入。文章通过简洁的代码示例和清晰的解释,帮助读者理解了如何通过注解的方式进行依赖注入,提高了开发效率。整体而言,本文深入浅出地介绍了IoC容器的增强和注解支持的实现方法,对于想要深入了解Spring框架的开发者来说,具有很高的参考价值。文章还提到了对BeanFactory接口的提取和抽象类的定义,以及MiniSpring的手写实现,展示了学习大师的做法和设计的重要性。同时,留下了思考题,引发读者对于框架的扩展性和多个注解支持的讨论。整体而言,本文内容丰富,技术性强,对于想要深入学习Spring框架的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《手把手带你写一个 MiniSpring》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(27)

  • 最新
  • 精选
  • 一念之间
    有一个简单的问题 为什么处理器要叫做PostProcessor呢? 这里的post到底是对于什么动作而言的呢?

    作者回复: post的字面含义是“什么什么之后”,这里是指create bean之后,用postProcessor进行修饰。

    2023-03-26归属地:上海
    3
  • 睿智的仓鼠
    通过这节课真的是感受到Spring设计的巧妙之处了,我目前的理解是,解耦分为两种:设计上的解耦、实现类上的解耦。通过抽取AbstractBeanFactory,把BeanPostProcessor的设计与BeanFactory本身解耦,AutowireCapableBeanFactory再通过定义BeanPostProcessor接口类型的属性,向外提供属性设置的方法,做到了和BeanPostProcessor实现类的解耦,最后在ClassPathXmlApplicationContext中统一注册BeanPostProcessor,再抽取成一个启动方法,非常优雅。AbstractBeanFactory的“接口抽象类”思想也很巧妙。这些思想在学Spring源码时早已听说,当时只觉得这样设计是灵活的,但不知道具体灵活在何处,通过自己手写实现下来真的是越来越清晰了,实属好课!

    作者回复: 赞!

    2023-03-21归属地:湖北
    3
  • 爪哇夜未眠
    文章里的代码,AbstractBeanFactory.doCreateBean()方法里,if (!constructorArgumentValues.isEmpty()) 后面少了一个else,里面是无参构造方法创建对象 else { obj = clz.newInstance(); }

    作者回复: 谢谢!

    2023-06-02归属地:北京
    2
    2
  • 杨松
    老师,请教下关于AutowiredAnnotationBeanPostProcessor的时机问题,为什么不是在处理属性handleProperties的位置,这个方法正好是设置bean实例的属性啊,我一直没弄懂为啥不放在这里?

    作者回复: 这个不是功能实现的问题,是时序规定的事情。第一步处理是根据配置的构造函数进行实例化,第二步是根据配置的properties给属性赋值,然后才到了后期修饰,而Spring统一用了一个beanpostprocessor机制来处理。三步一遍遍做完的。学习框架,功能实现不是最主要的,而是结构和时序,光说功能,不要框架也一样的。

    2023-04-14归属地:辽宁
    4
    2
  • 三太子
    https://github.com/yx-Yaoxaing/minispring/wiki/%E5%85%B3%E4%BA%8Emini-spring 自己写的代码提到github上 每日打卡! 遇到的基础问题 都写在了wiki

    作者回复: 赞

    2023-03-25归属地:重庆
    2
  • 马儿
    ClassPathXmlApplicationContext增加了一个BeanFactoryPostProcessor属性,本文中没有给出定义,看了GitHub源码把这个类拷贝出来。这个类的作用是什么呢?是像对BeanPostProcessor一样对BeanFactory进行特殊处理的吗?

    作者回复: 对的对的。这里没有用上,只是写了一个占位在这里,说明从时序上这儿可以进行对beanfactory的后期处理。这是当时留给学生的扩展练习。

    2023-03-22归属地:四川
    2
  • 陈小远
    跟到第四节了,单纯看文章逻辑来说还能理解一些实现,但是结合github上的源码(对照的是ioc4分支,不知道是否找对),发现源码和文章逻辑叙述的时候同一个类贴的代码实现是不一样的,导致对照学习的时候产生混乱。比如源码中AutowireCapableBeanFactory是直接实现的BeanFactory,但在文章的表述中是继承的AbstractBeanFactory,由此就在此节无法对照源码和文章表述自我参照着来完成注解的功能。看了四节后说说自己的一些看法或观点: 1、源码在github上,因为不是整个分支全克隆下来学习,单独的点击查看某个类的代码比较慢,影响学习效率,如果码云上有学习地址可能会好很多; 2、文章代码和源码不一致的问题不知道是跳跃太大还是个人没找对位置,很多人可能会渐渐的迷乱从而无法继续跟进学习; 3、源码相对于文章来说跳跃性比较大,如果正文中没法完全交代清楚,建议在源码的readme文件尽可能详细的给出一些突然出现的类的说明和设计意图 总的来说,通过老师的引导,再结合Spring的源码,还是有那么点感觉的,不过今天这节课实在没跟下来,可能还需要多花点时间自己琢磨琢磨

    作者回复: Github上的分支跟讲稿差不多对应的,但是不是完全一一对应上的,这是历史原因,几年前就放到Github上了,但是讲稿为了篇幅的规定又略微有些调整。你看的这部分是在ioc4中。每个分支里有一个docs/readme.txt文件,是当时边写的时候边手工做的记录。 你很用心,希望能跟下来,对自己大有益处的。

    2023-03-20归属地:四川
    3
    2
  • 怕什么,抱紧我
    老师: 1. Autowire注入对象B,此时B的beanDefinnition还没有加载进来,会报错!设置lazy = ture 也不行,只能把if( !beanDefinition.isLazyInit() )注释掉, 还有其它方法吗! 2.AutowiredAnnotationBeanPostProcessor#postProcessBeforeInitialization()方法: String fieldName = field.getName(); Object autowiredObj = this.getBeanFactory().getBean(fieldName); 这段代码,类的属性字段名要和xml配置的beanId相同,否则找不到!

    作者回复: 1.你看别的问题回复,这个问题讨论过了。 2.是的。因为这是简版,主要为了说明原理。

    2023-05-26归属地:湖南
    2
    1
  • 风轻扬
    老师,有几个问题请教一下。 1、AutowireCapableBeanFactory类中的addBeanPostProcessor为什么要先remove再add呢? 2、代码里出现异常的时候,老师都是只写一个try,这貌似不行吧,我是java8,这是高版本jdk的新特性吗? 3、AutowireCapableBeanFactory类中的invokeInitMethod方法,您的代码逻辑中,获取Class对象用的是BeanDefinition.getClass(),我理解,应该用Class.forName(BeanDefinition.getClassName()),init方法应该是我们业务类上定义的init方法吧?

    作者回复: 1,是不想重复 2,文稿中的代码不全,编辑当时建议只列关键代码。你要上Github找不同的分支,下载完整代码。 3,我用的是obj.getClass()。 init方法是业务类定义的初始化方法,名字在XML文件中配置。

    2023-03-22归属地:北京
    3
    1
  • Michael
    想请教一下老师,那现在是不是SimpleBeanFactory完全没用了?

    作者回复: 对。演变过程中会丢掉一些东西。

    2023-04-17归属地:陕西
收起评论
显示
设置
留言
27
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部