Spring的Ioc容器的实例化过程详解
依然还是针对Spring面试题的内容,这次我想记录下Spring容器是如何进行bean的加载以及整个容器初始化的过程理解,都是个人看书后的理解,如有不正确的地方,欢迎指正!
spring 的Ioc容器在通常意义上理解可以分为两类:BeanFactory 和 ApplicationContext;BeanFactory是Spring容器最初级的单位,而ApplicationContext是实现BeanFactory接口的一个针对web开发而产生的一个拥有更多spring定制功能的容器,如国际化、AOP;对于spring容器在开发中所起的作用就是将ConfigurationMetaData(配置信息,就是我们常用的Xml配置)中所有的信息包装成一个轻量化容器的过程;而这个过程我们可以简单划分为两部:1、容器的启动;2、Bean对象的实例化;
1、容器的启动包含:将所有xml配置中的<bean>标签元素当然也包含其他标签如<import>通过BeanDefinition类(叫做bean定义信息对象)进行封装,生成对应的BeanDefinition实例对象,然后调用BeanDefinitionRegistry的register方法将BeanDefinition加入registry容器中;
2、容器中bean的实例化:当所有beanDefinition对象都已经准备好之后,spring框架会在容器初始化时就调用getBean——》doGetBean——》createBean——》doCreateBean这个流程将所有的bean对象进行初始化过程,所有的bean对象最后存储的容器是DefaultListableBeanFactory;
概念:beanFactoryPostprocessor(容器启动阶段):BeanDefinition对象的后置处理器,在beanDefinition初始化之前,我们可以通过实现这个接口来修改对应的beanDefinition,也就是修改bean的初始定义信息;而且spring框架也为我们提供了一些beanFactoryPostprocessor的实现类,如PropertyPlaceholderConfigurer(属性占位符):在xml配置文件中我们可以把对数据库连接的动态配置抽离到properties文件中,方便后期对数据库的管理:${}美元符号这个属性占位符就可以动态加载propertis文件中有关数据库地址、用户、密码;
beanPostProcessor(bean的实例化阶段):bean对象的后置处理,在bean真正初始化之前,我们可以通过实现这个接口对bean的有关属性,或者方法进行修改,在spring中有AOP就是通过beanPostProcessor在bean创建之后创建bean的代理对象;
对于spring容器启动到bean初始化整个过程,spring都统一将这个过程放到了AbstractApplicationContext.refresh()这个方法中,读懂这个方法的核心步骤,也就理解了spring容器是如何启动并加载bean对象的;源码如下
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. /** * 做容器刷新前的准备工作 * 1、设置容器的启动时间 * 2、设置活跃状态为true * 3、设置关闭状态为false * 4、获取Environment对象,并加载当前系统的属性值到Environment对象中 * 5、准备监听器和事件的集合对象,默认为空的集合 */ prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // 创建容器对象:DefaultListableBeanFactory // 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // beanFactory的准备工作,对各种属性进行填充 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. // 调用各种beanFactorypostProcessor进行beanDefinition的增强处理 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 注册beanPostprocessor,这里只是注册功能,真正调用的是getBean方法(核心四步:getBean——>doGetBean——>createBean——>doCreateBean) registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的时候通过国际化的代码重点讲 initMessageSource(); // Initialize event multicaster for this context. // 初始化事件监听多路广播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 留给子类来初始化其他的bean onRefresh(); // Check for listener beans and register them. // 在所有注册的bean中查找listener bean,注册到消息广播器中 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 初始化剩下的单实例(非懒加载的) finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. // 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. // 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean destroyBeans(); // Reset 'active' flag. // 重置active标志 cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
以上有关spring容器的内容参考了《Spring揭秘》——作者:王福强 ;有兴趣的同学可以把那本书作为spring框架理解的核心书籍,个人所知道的spring核心功能本书都有提及;是加强个人基础功的好书

浙公网安备 33010602011771号