【Spring】IOC&DI:仿写核心流程小结

前篇:

先来说一下我们要使用的容器 MYApplicationContext 的继承关系,它实现了 BeanFactory 接口和 AbstractApplicationContext 抽象类

  • BeanFactory 接口:提供了 getBean(beanName) 和 getBean(beanClass) 两种获取 bean 实例的方法
  • AbstractApplicationContext 抽象类:核心是定义了 refresh() 方法,用于容器的初始化流程

注:这里只实现了 getBean(String beanName) 即通过 beanName 获取 bean,而 getBean(Class<?> beanClass) 通过 Class 获取 bean 还没有写,但逻辑是没差别的。

来看下面这行代码做了什么:

MYApplicationContext context = new MYApplicationContext("classpath:application.properties");

1)在 MYApplicationContext 的构造函数中,将配置文件路径保存到成员变量 configLocations ,然后调用 refresh() 创建并初始化一个 IOC 容器

2)refresh() 创建并初始 IOC 容器大致逻辑如下:

  1. 定位:加载配置文件,将文件中配置的类/扫描的包的全类名保存下来(PS:在Spring中这部分工作是Resource相关类)
  2. 加载:根据配置信息,将扫描到的所有类加载成 BeanDefinition(PS:关键信息 beanName、beanClass、isLazyInit、isSingon)
  3. 注册:将 List<beanDefinition> 根据注册到 beanDefinitionMap<String,BeanDefinition>,key 是 beanName(注:为了 getBean(Class) 这里本来还应该再按 beanClass 注册一次)

3)在 refresh() 的最后会调用 doAutowired() 去进行创建实例和依赖注入,而这些逻辑都是封装在 getBean() 方法中

注:所以,在初始化 IOC 容器时进行 bean 创建和依赖注入是有前提的,即该 bean 不是懒加载(默认非懒加载)

  1. 创建 bean 实例

    1. 根据 beanName 获取 BeanDefinition,如果没有 BeanDefinition,则代表该 bean 不是 IOC 容器管理的
    2. 根据 BeanDefinition 保存的 beanClass 反射创建实例对象
    3. 如果该 bean 是单例模式,则将该 bean 注册到 factoryBeanObjectCache<String,Object>,key 是 beanName
    4. 将实例对象包装成 BeanWrapper(包括 instance 和 class),然后注册到 factoryBeanInstanceCache<String,BeanWrapper>,key 是 beanName
  2. 执行依赖注入 populateBean()

    1. 获取当前 bean 的所有成员变量,并判断哪些字段标识了 @Autowired 注解
    2. 对标有 @Autowired 的注解的字段,从 factoryBeanInstanceCache 获取 bean 实例,然后通过反射进行注入(注:@Autowired 本来应该是按照 class 注入,但是这里没实现,所以使用的 byName 注入)
  3. 通过 factoryBeanInstanceCache#get(beanName) 返回目标对象

注:无论是单例还是多例,每次 getBean() 都会创建一个新的 BeanWrapper,然后放到 factoryBeanInstanceCache

  • 对于单例,在创建 bean 实例时,之前创建过实例了,则会从 factoryBeanObjectCache 中取(已经完成依赖注入的);而多例则是每次都要重新创建一个 instance,再执行依赖注入(默认单例)
  • 虽然都都会再放入 factoryBeanInstanceCache 这个 Map 中,但是 beanName 这个 key 没变,所以会覆盖之前的

再看这行代码又干了什么:

Object bean = context.getBean("myAction");

对于这里的 getBean()

  • 由于该 bean 是非懒加载的,所以实例对象其实已经创建好,并且也完成了注入
  • 由于该 bean 是单例的,所以会直接将已经创建好并完成注入的 bean 返回

猜你喜欢

转载自blog.csdn.net/weixin_43935927/article/details/114190853