Spring源码分析之仿BeanFactory原理实现

参考某个大神的分解Spring源码,具体的github地址给忘记了。后续补上

加入我自己的理解,如果让你写Spring的BeanFacotory,你是否也会想到这么写?

Step1:

         我们知道,spring就是一个大容器(工厂),里面放置了spring初始化的bean,我们需要需要获得该bean时,直接从spring容器中取就OK了。所以,我们大致描述为:

Spring源码分析之仿BeanFactory原理实现_第1张图片

BeanDefine类表示在spring中怎样定义该bean的。

BeanFactory表示bean工厂,beanDefinitionMap中存放keyàbeanName,valueàBeanDefinition,getBean方法通过beanName获取到该定义的Bean,registerBeanDefinition是通过key,value形式将bean放在工厂中。

Step2:

         但是,该bean需要我们手动实例化,并放在spring容器中。在spring中,bean的实例化是由spring自动管理的,我们只需要提供类的全限定名即可。所以,我们继续改为如下:

Spring源码分析之仿BeanFactory原理实现_第2张图片

 

BeanDefine:我们继续增加两个属性,beanClassName就是我们需要放在spring bean工厂的类名,spring会通过反射机制实例化该bean

BeanFactory:此外,我们也需要做一些拓展了,将其方法交给实现类AbstractBeanFactory,由AbstractBeanFactory的子类去创建一个bean。。

Step3:

         这时,我们还得考虑另外的问题:类中是有属性的, 按照我们常规的观念:

BeanObject obj = new BeanObject(); obj.setProperties(“abc”);

spring一个典型的功能就是实现IOC(或者说依赖注入DI),我们初始化一个bean时,不仅要实例化该类,还得注入其属性值。

         所以,我们继续改造:

Spring源码分析之仿BeanFactory原理实现_第3张图片

BeanDefine:我们增加一个PropertyValues(是一个PropertyValue的List),表示该bean还有若干属性。PropertyValue:keyà属性名,valueà属性值

此时,在AutowireCapableBeanFactory创建一个bean时,分为两步了:先createBeanInstace(通过反射创建bean对象),而后applyPropertyValues(同样通过反射注入属性值到属性里面)。

Step4:

         但是这样,在客户端我们依然要通过PropertyValues设置属性的值。在spring中是通过xml或者注解的方式直接注入。

         所以,我们将属性注入改为xml配置。。

Spring源码分析之仿BeanFactory原理实现_第4张图片

这时我们需要新写一个工厂(BeanDefinitionReader)来读取我们的配置文件,从而生成bean。

loadBeanDefinitions(String location)就是很据配置文件的位置(location),读取到registry(是一个Map(beanName,beanDefinition))。其大致流程为:

         先用ResourceLoader获取到文件的路径(相对路径哦),并转为InputStream对象。。

         而后使用Xml解析器(如:dom4j,sax[这里使用了]),解析了该xml,将xml配置为内容对应到BeanDefinition的ClassName,PropertyValues中去。。

         最后再使用BeanFactory生成bean,跟第三步一样。。

Step5:

可发现,之前我们的注入都是一些常规值。在spring中,我们经常遇到的就是一个bean依赖另外一个bean。比如service层里就是引用dao层。所以,继续改造如下:

Spring源码分析之仿BeanFactory原理实现_第5张图片

 

 

对比第4步,基本上没什么大的改动。

增加了一个类BeanReference,保存bean的名name,以及bean对象

此时就需要该两处逻辑了:

1、  XmlBeanDefinitionReader中的processProperty方法,(该方法就是将解析后的xml根据节点属性值传给PropertyValue),我们还需要判断是否是ref属性,如果是则将该属性封装成BeanRefrence,其他同第四步

2、  在AutowireCapableBeanFactory的applyPropertyValues方法中,同样需要判断属性值是否为BeanReference类型,如果是,通过beanReference得到bean,注入到bean属性中。、

我们写个测试:(step01-step04均未写测试方法,你可以看下附件。主要我想着在这里的测试方法基本上能涵括上面所有步骤了)

@Test

         public void test01() throws Exception{

                   XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());

                   xmlBeanDefinitionReader.loadBeanDefinitions("li/wei/craftTest/xml/step05.xml");

 

                   // 2.初始化BeanFactory并注册bean

                   BeanFactory beanFactory = new AutowireCapableBeanFactory();

                   for (Map.Entry beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {

                            beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());

                   }

                  

                   UserService bean = (UserService) beanFactory.getBean("userService");

                   bean.sayWord();

                   bean.sayName();

         }

 

Step6:

         经过上面几步,我们完成了spring的核心内容àBeanFactory。基本上完成了spring的bean工厂生成bean的整个流程。

         观察上面的测试方法,基本也没什么问题。但是,你会发现,实例化BeaFactory,怎么加载配置文件,都得需要我们手动指定。为此,我们得考虑让spring去读取我们的资源,自动初始化BeanFactory。。

         如果说之前我们完成了spring的心脏(BeanFactory),接下来我们还得为spring造身体àApplicaitonContext

Spring源码分析之仿BeanFactory原理实现_第6张图片

(UML图做了一些调整,删除了一下不太重要的关联。还是基于Step05)

这时,我们就可以将spring加载我们的配置(xml)交给ApplicationContext,并且ApplicationContext加载好配置后,就会调用refresh()方法,该方法会直接调用BeanFactory的 registerBeanDefiniation(),初始化我们的bean工厂。这时我们就直接可以使用getBean()方法直接获取到我们的bean了。。

你可能感兴趣的:(Spring源码分析之仿BeanFactory原理实现)