您现在的位置是:源码分析

spring源码 IOC容器的初始化及获取

  • 乐哉码农
  • 源码分析
  • 2019-05-19 14:20:51
  • 1209人已阅读
摘要spring源码 IOC容器的初始化及获取

最近花了点时间学习了下spring的源码,通过各种途径,现在已经知道spring从初始化到通过getBean方法获取容器中实例的大致过程了,

1.首先我先创建一个简单的spring项目,方便我们进行源码的跟踪调试

ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");

Test bean = context.getBean(Test.class);

System.out.println(bean.hello());

2.进入到ClassPathXmlApplicationContext的构造器中,发现里面有两个方法

this.setConfigLocations(configLocations);

if(refresh) { this.refresh();}

3.先通过setConfigLocations将我们传入的配置文件配置到变量中去保存,然后IOC容器的初始化入口就是从refresh方法开始

4.refresh方法是他的基类AbstractApplicationContext实现的,点进去看下里面都做了什么

this.prepareRefresh();

ConfigurableListableBeanFactory beanFactory =this.obtainFreshBeanFactory();

this.prepareBeanFactory(beanFactory);

try {

this.postProcessBeanFactory(beanFactory);

this.invokeBeanFactoryPostProcessors(beanFactory);

this.registerBeanPostProcessors(beanFactory);

this.initMessageSource();

this.initApplicationEventMulticaster();

this.onRefresh();

this.registerListeners();

this.finishBeanFactoryInitialization(beanFactory);

this.finishRefresh();

5.首先进入到第一个方法里面this.prepareRefresh();,先进行了属性资源的初始化,然而spring并没有实现这个方法,

this.initPropertySources();//初始化属性资源

this.getEnvironment().validateRequiredProperties();//验证环境

6.现在开始创建beanfactory,在这里面会对beanfactory进行初始化和加载BeanDefinitions

ConfigurableListableBeanFactory beanFactory =this.obtainFreshBeanFactory();//spring 默认的beanfactory是

this.prepareBeanFactory(beanFactory);

在obtainFreshBeanFactory方法中会去调用基类AbstractRefreshableApplicationContext的refreshBeanFactory方法拿到spring默认实现的DefaultListableBeanFactory,

6.拿到beanfactory之后,我们就可以调用loadBeanDefinitions 加载我们配置文件中定义的beandefinition配置信息了,

加载beandefinition需要三个步骤:定位、加载、注册

XmlBeanDefinitionReader beanDefinitionReader =new XmlBeanDefinitionReader(beanFactory);

通过创建beanDefinitionReader读取器用来读取配置信息,

在这里面会有一个判断,因为我们在最开始的时候传入的是一个配置文件名称,被设置到了configlocations里面去,所以这里会调用后者进行配置文件的加载


 

 


 

现在进行配置文件的定位,通过创建一个资源处理器,将我们设置的location传入,


 

真正对资源文件进行处理的是在XmlBeanDefinitionReader 中,读取配置文件,按照一定规则进行解析,得到了配置文件中所有的bean并注册到了beanDefinitionMap中,


 

可以在默认beanfactory中的registerBeanDefinition中看到注册过程


 

7.拿到beandefinitions配置信息后,就需要进行后续的初始化了

这三个方法分别是注册beanfactory的前置处理器和bean的前置处理器,都是可以自己进行定义;只需要在配置资源中进行配置就可以被IOC发现,并注册进去,String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class,true,false),获取BeanPostProcessor的所有继承者。


 

8.进行广播器的注册,如果在bean有定义过这个名称,就会用自己定义的if(beanFactory.containsLocalBean("applicationEventMulticaster")) {

9.onRefresh()这个方法并没有在子类中实现它

10.registerListeners 注册我们在IOC容器中配置的所有实现ApplicationListener这个接口的监听器

11.finishBeanFactoryInitialization

我们所有bean的实例化都是在第一次使用getBean方法获取的时候进行初始化的,但是有一种情况是在IOC容器初始化之后紧接着就进行bean的实例化,通过标注scope的值是单例的,就会在finishBeanFactoryInitialization方法中调用preInstantiateSingletons提前初始化,默认所有的bean都是单例的,所以在这里大部分的bean都被实例化了。

12.preInstantiateSingletons,

①首先遍历所有的beanname,根据beanname调用getSingleton方法进行搜索,需要时配置了非懒加载,单例,不是抽象才会提前初始化


 

②根据bean的名字拿到对应的RootBeanDefinition,然后调用getBean方法进行实例化


 

13.doGetBean(真正获取bean的方法)

①先从缓存中获取到已经注册的最原始的bean,看是否能获取到

        Object sharedInstance =this.getSingleton(beanName);

②如果不为空,则再调用getObjectForBeanInstance获取factorybean处理后的bean(如果当前bean是factorybean的话),否则返回原始bean

③如果为空的话,则从当前的beanfactory去找,如果还是没有找到则继续沿着链进行寻找,如果还是找不到,则会执行creatbean方法进行创建,并查找他所依赖的实例,使用递归去调用getBean方法获取,直到所有依赖实例都没实例化为止。

 


④创建bean


 

resolveBeanClass()判断当前的是否可以初始化、是否可以通过类装载器来载入

resolveBeforeInstantiation,如果配置了InstantiationAwareBeanPostProcessor的话,则会返回代理后的对象

进入到doCreateBean方法,

        首先清除缓存中同名的bean,并创建

if(mbd.isSingleton()) {

instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);

}

if(instanceWrapper ==null) {

instanceWrapper =this.createBeanInstance(beanName, mbd, args);

}

通过以上步骤完成了bean的实例化,现在准备对bean进行初始化,依赖注入、属性的初始化等

* this.populateBean(beanName, mbd, instanceWrapper);

 

在执行完populateBean,对实例进行基本的属性注入等初始化完毕后,就开始执行进一步的initializeBean()

先看下方法内部做了哪些操作

①先判断目标类是继承了感知类,如果继承了则调用invokeawaremthod方法进行设置


 

 

②然后在初始化之前调用前置处理器的方法


 

遍历所有的前置处理器,依次执行


 

③前置处理器执行完毕开始执行初始化,

处理自定义的初始化方法


 

④执行后置处理器

 


 

 


 

整个流程到此分析结束,大致流程就这样了,并没有细致的进行深入分析。

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章评论

Top