2.自动创建bean对象
🤔 2.自动创建bean对象
本节中主要是以上一节为基础,并对上一节制作的IOC容器进行改良,上一节中,bean对象的实例化是手动new出来的,这一节中将bean对象的创建交给IOC容器本身,并且为了考虑扩展性,尽可能的使得每一个类都只执行一个职责,最终让整个项目变得更加健壮,本节中创建的bean默认单例。关于项目的源码存放在 仓库 中
思路
本节就是在上一节的基础上将bean的创建交给了IOC容器,并且实现了一个单例模式(默认)的bean,具体的设计图如下:
可以看出,只是在定义、注册、获取的基础上多了几个模块,例如获取bean对象的时候要判断是否已经存在,存在直接返回,不存在就创建再返回等。。。项目的核心类图如下:
下面依次针对每一个类进行讲解
类的说明
SingletonBeanRegistry
:是一个接口,只是提供了一个待实现的getSingleton(String beanName)
方法,后期获取bean对象时调用getBean
方法,内部调用这个方法,尝试获取一个单例模式的bean,方法的实现在DefaultSingletonBeanRegistry
类中,主要就是从容器中按照bean对象的名称尝试获取bean对象,对象不存在返回值为nullDefaultSingletonBeanRegistry
:是SingletonBeanRegistry
的实现类,类中有如下方法:内部有一个名为
singletonObjects
的HashMap容器,主要存储已经实例化后的bean对象及其名称之间的映射关系,主要实现了getSingleton(String beanName)
方法,并且还增加了一个addSingleton(String beanName, Object singletonObject)
方法,主要作用是对外提供一个保存实例化后的bean对象的api,在AbstractAutowireCapableBeanFactory
类中的createBean(String beanName, BeanDefinition beanDefinition)
中使用,主要作用是将利用反射创建的bean对象保存到容器中,使的bean变成单例BeanFactory
:是一个接口,提供了一个待实现的getBean(String name)
方法,对外暴露之后,可以实现从IOC容器中尝试获取一个单例模式的bean对象AbstractBeanFactory
:继承了DefaultSingletonBeanRegistry
类,实现了BeanFactory
接口,类中现有如下方法:主要是实现了
getBean(String name)
方法,根据名称尝试获取实例化之后的 bean对象,内部调用继承的getSingleton
方法尝试获取一个单例模式的bean对象。不存在的话就调用继承的createBean
方法创建并返回一个bean对象,也就是先调用,不存在就创建AbstractAutowireCapableBeanFactory
:主要是将继承下来的createBean(String beanName, BeanDefinition beanDefinition)
方法实现了,内部使用反射机制从BeanDefinition
中取出bean的类信息从而利用反射创建一个实例对象(此时这个对象还没有属性),并且调用addSingleton
方法将其保存到singletonObjects
中,类的结构如下:需要注意的是,这里创建的是最简单的bean对象,无法在创建对象时传递参数,本项目只是实现了两个功能,一个是将bean的创建交给IOC容器,一个是创建的bean保证是单例模式的,后期会实现带参的对象构建,正常来说就实现创建无参的bean对象,然后进行属性填充
BeanDefinitionRegistry
:是一个接口,主要提供了一个待实现的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
方法,用来注册bean,也就是将bean的名称与其类信息绑定到一起,使用一个HashMap存储,实现类在DefaultListableBeanFactory
中,类的结构如下:DefaultListableBeanFactory
:项目中最核心的一个类,通过一层一层的叠加,每一个类都实现自己的功能,然后在这个类中将其他所有的类的功能集成在一起,形成的类结构如下:所有的已实现的方法被集中到了这一个类中,外部直接通过这个类调用这些已实现的api即可,这就是项目结构中最底层类的好处,最底层类对外暴露,使得所有的方法都可以继承被使用
bean的创建和获取
为了将bean的创建交给IOC容器,回想一下学过的知识,不手工new还能得到对象的方法就是反射,所以这里我们在注册时,也就是BeanDefinition时保存的不再是bean对象,而是一个类的信息,后期IOC容器可以通过这个类信息使用反射
的知识来创建一个bean对象
并且平时在使用spring框架搭建项目时,bean可以选择很多模式,比如singleton
,prototype
,本节中就简单的实现单例模式的bean对象创建,为了实现单例模式,需要进行判断,当获取bean对象,对象不存在时,直接创建,并且底层需要将这个创建的bean对象保存到一个容器中,后期再次使用的时候,直接拿出这个已经创建过的对象,这样就不会反复的创建新的bean对象,从而实现单例模式,核心代码如下:
|
|
bean存在时直接返回,不存在时创建了再返回
需要注意的是,获取bean对象的时候,经历了如下的流程:
并且创建bean的过程中,只创建了无参数的bean,一旦想要创建bean的时候让bean携带一些参数,就会出现异常,也就是说现在还无法创建带参数的bean,如何解决,看下一节!
总结
为了实现将bean的创建交给IOC容器,本项目做了如下几点工作:
- 注册bean的时候,保存的不再是实例化后的bean,而是bean的类信息,在需要的时候通过反射利用类信息创建一个实例即可
- 为了实现单例模式的bean创建,调用一些方法,存在就返回,不存在就创建,并且创建之后将实例化后的bean保存到一个容器中,后期随用随取
- 为了增强程序的健壮性,将单例模式的IOC容器的各个功能进行划分,每个类只做自己的事情,通过继承将这些方法得到,一层一层的逐步实现,最后最底层的类就集成了所有的方法,直接调用api就可以实现相应的功能
项目中的文件分为两类,一类是提供统一接口、模版或者全局都会使用的配置文件,一类是实现具体功能的支持文件,文件的主要结构如下:
每个类只做自己的工作,将业务逻辑区分开,核心就是整体的类图,这个类图将整个项目的功能拆分开,每个类实现一个功能,最后将这些功能集成到同一个类中
本文只是做了两个工作:
- bean的创建交给IOC容器
- bean的创建保证是单例模式
下一节中将解决创建bean对象时无法创建携带参数的bean对象,也就是无法利用有参构造创建bean对象的问题