初窥Spring源码之IOC

 2023-01-20
原文作者:亚雷 原文地址:https://juejin.cn/post/7124896916382908446

1. 控制反转

学过Spring之后,我们都知道,Spring有两大核心,一个是IOC(控制反转)一个是AOP(横向编程)

我们先来聊聊控制反转

        我们刚听到这个词之后第一反应就是什么控制被反转了?
        在这个地方我是这样理解的,依赖对象获得的控制权限被反转了,所以我们也叫依赖注入

在日常的开发中,我们在实现业务的时候,通常需要多个类来实现最终我们想要的结果,如果这些对象的获取都让我们自己手动完成,我们的代码将会有很多冗余,耦合极其高!所以Spring的IOC容器应运而生,同样的我们需要知道,SpringIOC只是依赖注入的一种实现方式,这种原理在其他语言的应用也有很多,但因为我太菜,并不知道。。。

2. Spring中的IOC

其实在Spring中有很多IOC的实现方式,例如我们经常接触到的 BeanFactoryApplicationContext ,但是我们IOC不仅仅只是这两种,就像我们有点渴了,想去超市买点水,然后超市有很多种水,矿泉水,可乐等等,Spring中的IOC也是这样,而BeanFactory是SpringIOC功能的基本规范,而Spring为了满足不同场合的需要,也提供了很多实现。

2.1 BeanFactory

我们先看BeanFactory和ApplicationContext的类图,我们可以看到ApplicationContext这个接口继承于BeanFactory的子接口,我们可以认为ApplicationContext间接继承于BeanFactory,可以认为ApplicationContext是对于BeanFactory的一种功能扩展,而这功能扩展很明显来自于另外的接口也就是其他四个接口。

202301012015096431.png 我们需要知道,BeanFactory才是Spring的核心容器类

我们可以看到BeanFacotry里面定义了获取Bean的方法,以及判断Bean对象的方法,可以简单理解为BeanFacotry封装了对于Bean对象的管理方法

202301012015104142.png

我们再来看看HierarchicalBeanFactory接口的方法,我们从上面的类图可以看到这个接口是BeanFacotry的一个子类,这个接口的第一个方法是返回当前BeanFacotry的父BeanFacotry,而第二个方法可以与BeanFacotry中的containBean方法做类,containBean方法会去查找当前BeanFactory是否有包含name的bean对象,如果不包含,那么会去父的BeanFactory中查找是否有包含name的bean对象,而containsLocalBean仅仅查看当前BeanFactory中是否存在name的bean对象,不会去父类中去查找

202301012015109263.png

我们再看ListableBeanFactory接口,这个类名直译为能列出的beanFactory列表,当然这个接口并没有列出所有bean对象的方法,很显然也没有这个需求,它可以返回指定类型的所有实例,也就对应着下面的方法

202301012015114224.png

2.2 ApplicationContext其余父类

我们可以看到ApplicationContext还继承于EnvironmentCapable,ResourcePatternResolver,ApplicationEventPublisher,MessageSource,这四个类都是对于ApplicationContext功能上面的增强

202301012015119435.png

  • MessageSource:是对于国际化语言的一种支持功能上的增强
  • ResourcePatternResolver:对于classpath下面类路径通配符资源的一种功能增强
  • ApplicationEventPublisher: 事件发布功能增强
  • EnvironmentCapable: 环境变量读取的功能增强

202301012015123826.png

这个事件发布功能,这个功能类似于异步通信,我们可以把他想象成消息队列,只不过这个消息队列是对于应用中的,而不像消息队列,是对于服务于服务的。

3.BeanFactory的实现

我们先看看BeanFactory的类关系图

202301012015129237.png

我们可以看到最终的实现类是XmlBeanFactory,但是这个类很明显已经被弃用了,我们只关心他的父类即可,也就是DefaultListableBeanFactory类,我们可以认为这个DefaultListableBeanFactory就是我们在Spring中使用的IOC容器,我们都知道我们要把对象交给SpringIOC来管理肯定要将对象注册到IOC容器里面,但是我们怎么放呢?应该放什么呢?取的时候怎么拿呢?这些是我们需要了解到的,我们常用的注册Bean对象的方法有使用@Component等一系列注解,然后让Spring去扫描这些注解,然后让IOC来管理这些Bean对象,还有使用@Bean注解返回一个实例对象,还有使用xml文件,然后让Spring解析xml文件来注册Bean对象,这种方法我们现在并常用,但是我们仍然需要知道

我们回到之前的三个问题

  • 到底该怎么放Bean对象?
  • 应该放Bean对象的什么东西?
  • 我们需要的时候该怎么去拿?

这三个问题是我们需要考虑的,很明显我们让IOC来管理Bean对象的时候,对于不同的Bean我们都是要定义不同的属性的,否则我们取的时候并不知道我们到底取的是哪个,这些Bean对象的定义都是些什么呢?肯定要有Type,name,因为我们经常使用的@Autowired注解默认就是byType的,@Qualifier是byName的,所以这些是必须的,我们定义Bean对象的时候,我们还需要设置作用域(scope),这个是也是必须的,是不是这些就够了?其实不然,我们不要忘了IOC的作用是什么,控制反转,所以肯定要有Bean对象的初始化和销毁!

而在Spring中是怎么怎么来定义这些东西呢?AbstractBeanDefinition这个类是专门用来定义Bean对象的类,我们可以看到这个类是一个抽象类,所以我们用的时候使用的是GenericBeanDefinition这个类,这个类是他的一个子类,我们可以通过类图看到,而这个类通过BeanDefinitionBuilder类的genericBeanDefinition方法拿到。

202301012015135428.png

202301012015140389.png

这里可以看到他有四个重载方法,这四个方法都是获取Bean定义的,常用的有两个分别对应者bean的class名,bean的class类型,这里第四个方法的第二个参数,我也不太明白这个是什么作用,查阅资料得出是用于创建Bean实例的回调,还是不太明白,如果有人知道,望告知

2023010120151456510.png

然后我们定义之后,我们需要把这个Bean定义注册到IOC中,也就是BeanFactory中,然后我们就能获取我们放入到IOC中的Bean对象了

不过这个时候我们的IOC容器还仅仅只能拿到我们手动添加到IOC容器的Bean对象,但是并不能拿到我们使用注解标记的Bean对象,例如@Bean,@Configruation,这个时候后处理器的作用就显现出来了,我们需要先把后处理器注册到BeanFactory中,这些后处理器都有什么呢?他们的作用是解析注解例如@Bean、@Autowried等等

我们可以通过这个方法把这些后处理器都注册到BeanFactory

    AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFacotry);

但是需要注意的是,我们仅仅将这些后处理器注册到BeanFactory中是不行的,他们还没有生效,我们需要执行这些后处理器才能生效

4.小结

对于BeanFactory的实现这里已经差不多很明确了

        先去创建一个BeanFactory,然后将Bean对象放入这个IOC容器中
        也就是BeanFactory,然后提供了getBean方法
        并且可以添加后处理器,后处理器的作用是用于解析一些注解用于注入Bean或者放入IOC中