仅记录本人学习,欢迎交流
序言
定义:IoC(Inversion of Controller,控制反转)就是将原本代码里需要实现的对象创建、依赖,反转给容器来帮忙实现。我们需要创建一个容器,同时需要一种描述来让容器知道要创建的对象与对象的关系。这个描述最具体的表现就是我们所看到的配置文件
基于XML的IOC容器初始化 _IoC初始化包括BeanDefinition的Resource的三个阶段:定位、加载、注册
定位:寻找入口、获取配置文件路径、容器启动加载:解析配置文件路径、载入配置文件路径注册:将配置文件解析为BeanDefinition存储bean定义配置信息流程如下: 寻找入口、获取配置文件路径、开始启动、创建容器、载入配置路径、分析路径处理策略、解析配置文件路径、读取配置文件、准备文档对象、分配解析策略、将配置载入内存、载入Bean标签元素、载入property标签元素、载入priperties标签子元素、载入list标签元素、分配注册策略、向容器注册
Spring中Bean的创建是典型的工厂模式,BeanFactory定义了IoC容器的基本功能实现。在BeanFactory中只对IOC容器的基本行为做了定义,根本不关系Bean是如何定义以及怎样加载的。要知道工厂是如何生产对象的,我们需要看绝体的IoC容器实现。
本文以ClasspathXmlApplicationContext为例,ApplicationContext是Spring提供的一个高级的IoC容器
各种配置文件到内存中都会变成BeanDefinition Srping IoC容器管理我们定义的各种Bean对象以及其相互关系,Bean对象在Spring实现中是以BeanDefinition来描述的
由BeanDefinitionReader来解析配置文件
简单说,就是读取配置文件,找到需要加载到IOC容器中的Bean
项目启动时加载DispatcherServlet,其调用父类的init()方法进行初始化。
@Override public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } // Set bean properties from init parameters. try { // 获取servletConfig,定位资源文件 PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); // 将dispatcherServlet对象封装到BeanWrapper类里,加载配置细腻些 BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); // 获取servletContext ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); // 空的方法 initBeanWrapper(bw); bw.setPropertyValues(pvs, true); } catch (BeansException ex) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); throw ex; } // Let subclasses do whatever initialization they like. //是真正初始化容器动作的代码 initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } }其中initServletBean()是真正完成初始化webApplicationContext动作的,这里不进行详细讲解,会在SpringMVC时序图中详解。 继续跟进代码,会看到在configAndRefreshWebApplicationContext()方法中调用了**refresh()**方法进行bean初始化
梦开始的地方,通过构造方法启动 此类做了以下三项重要的工作
首先调用夫容器的构造方法为容器设置好Bean资源加载器然后调用父类的setConfigLocations(configLocations)方法设置Bean配置信息的定位路径等加做完以上动作后,开始调用父类AbstractApplicationContext的refresh()方法启动整个IoC容器对Bean定义的载入过程 public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { //调用父容器的构造方法为容器设置好Bean资源加载器 super(parent); //设置Bean定义资源文件、配置信息的路径 setConfigLocations(configLocations); if (refresh) { //重启、刷新、重置。对Bean配置资源的载入 refresh(); } }refrresh()方法主要作用是:在创建IOC容器前,如果已经有容器存在,需要把已有的容器销毁和关闭,以保证refresh()方法之后使用的是新创建的IOC容器,它类似于对IOC容器的重启,在新创建的容器中对容器进行初始化,对Bean配置资源进行载入。 主要为IoC容器Bean的生命周期管理提供条件,SpringIoC容器载入Bean配置信息从其子类容器的refresgBeanFactory()方法启动: ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //1、调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识 prepareRefresh(); //2、告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从 //子类的refreshBeanFactory()方法启动 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //3、为BeanFactory配置容器特性,例如类加载器、事件处理器等 prepareBeanFactory(beanFactory); try { //4、为容器的某些子类指定特殊的BeanPost事件处理器 postProcessBeanFactory(beanFactory); //5、调用所有注册的BeanFactoryPostProcessor的Bean invokeBeanFactoryPostProcessors(beanFactory); //6、为BeanFactory注册BeanPost事件处理器. //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件 registerBeanPostProcessors(beanFactory); //7、初始化信息源,和国际化相关. initMessageSource(); //8、初始化容器事件传播器. initApplicationEventMulticaster(); //9、调用子类的某些特殊Bean初始化方法 onRefresh(); //10、为事件传播器注册事件监听器. registerListeners(); //11、初始化所有剩余的单例Bean finishBeanFactoryInitialization(beanFactory); //12、初始化容器的生命周期事件处理器,并发布容器的生命周期事件 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } //13、销毁已创建的Bean destroyBeans(); //14、取消refresh操作,重置容器的同步标识。 cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { //15、重设公共缓存 resetCommonCaches(); } } }obtainFreshBeanFactory()方法中,调用了子类的refreshBeanFactory()方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法 refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }到此为止定位阶段结束,开始进入加载阶段
本次源码之旅主要针对xml形式,故继续跟进AbstractXmlApplicationContext中的loadBeanDefinitions()方法。
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { //创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); //为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的 //祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器 beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); //为Bean读取器设置SAX xml解析器 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制 initBeanDefinitionReader(beanDefinitionReader); //Bean读取器真正实现加载的方法 loadBeanDefinitions(beanDefinitionReader); }