Spring之Spring IoC时序图

仅记录本人学习,欢迎交流

序言

定义:IoC(Inversion of Controller,控制反转)就是将原本代码里需要实现的对象创建、依赖,反转给容器来帮忙实现。我们需要创建一个容器,同时需要一种描述来让容器知道要创建的对象与对象的关系。这个描述最具体的表现就是我们所看到的配置文件

基于XML的IOC容器初始化
_IoC初始化包括BeanDefinition的Resource的三个阶段:定位、加载、注册

  • 定位:寻找入口、获取配置文件路径、容器启动
  • 加载:解析配置文件路径、载入配置文件路径
  • 注册:将配置文件解析为BeanDefinition存储bean定义配置信息

流程如下:
寻找入口、获取配置文件路径、开始启动、创建容器、载入配置路径、分析路径处理策略、解析配置文件路径、读取配置文件、准备文档对象、分配解析策略、将配置载入内存、载入Bean标签元素、载入property标签元素、载入priperties标签子元素、载入list标签元素、分配注册策略、向容器注册

时序图预览

Spring IoC时序图

一、核心类

1、BeanFactory

Spring中Bean的创建是典型的工厂模式,BeanFactory定义了IoC容器的基本功能实现。在BeanFactory中只对IOC容器的基本行为做了定义,根本不关系Bean是如何定义以及怎样加载的。要知道工厂是如何生产对象的,我们需要看绝体的IoC容器实现。

本文以ClasspathXmlApplicationContext为例,ApplicationContext是Spring提供的一个高级的IoC容器

2、BeanDefinition

各种配置文件到内存中都会变成BeanDefinition
Srping IoC容器管理我们定义的各种Bean对象以及其相互关系,Bean对象在Spring实现中是以BeanDefinition来描述的

3、BeanDefinitionReader

由BeanDefinitionReader来解析配置文件

二、定位

简单说,就是读取配置文件,找到需要加载到IOC容器中的Bean

1、DispatcherServlet

项目启动时加载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初始化

2、ClassPathXmlApplicationContext

梦开始的地方,通过构造方法启动
此类做了以下三项重要的工作

  • 首先调用夫容器的构造方法为容器设置好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;
	}

3、 AbstractRefreshableApplicationContext

  • 首先判断beanFactory是否存在,如果存在则先销毁Bean并关闭beanFactory
  • 接着创建DefaultListableBeanFactory
  • 并调用loadBeanDefinitions()方法装载Bean定义
@Override
	protected final void refreshBeanFactory() throws BeansException {
		//如果已经有容器,销毁容器中的bean,关闭容器
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			//创建IOC容器
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			//对IOC容器进行定制化,如设置启动参数,开启注解的自动装配等
			customizeBeanFactory(beanFactory);
			//调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

到此为止定位阶段结束,开始进入加载阶段

二、加载

1、AbstractXmlApplicationContext

本次源码之旅主要针对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);
	}

三、注册

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程大帅气

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值