spring源码分析之Ioc

前言

Spring 是分层的 full-stack(全栈) 轻量级开源框架,以 IoC 和 AOP 为内核,提供了展现层 SpringMVC 和业务层事务管理等众多的企业级应⽤技术,还能整合开源世界众多著名的第三⽅框架和类库,已经成为使⽤最多的 Java EE 企业应⽤开源框架。因此无论在以后面试还是工作学习中,都是很重要的,学习知识可能最开始我们只是知道怎么用,但在熟练使用之后,我们需要去看一下源码是如何实现的,体会框架的思想并学习,提升自己的编程思想与能力,因此本文就从源码阶段介绍一下spring的ioc执行流程。欢迎大家多多指教!

一、源码阅读的技巧

  1. 好处:提⾼培养代码架构思维、深⼊理解框架
  2. 原则
    定焦原则:抓主线
    宏观原则:站在上帝视⻆,关注源码结构和业务流程(淡化具体某⾏代码的编写细节不然会迷失在源码中,跳不出来,开始奔溃!)
  3. 读源码的⽅法和技巧
    A. 断点(观察调⽤栈)
    B. 反调(Find Usages)
    C. 经验(spring框架中doXXX,做具体处理的地⽅

二、IOC中关键的接口和类

1.BeanFactory

Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化(它是接口),它定义了所有 IoC 容器 必须遵从的⼀套原则,具体的容器实现可以增加额外的功能,⽐如我们常⽤到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容,AnnotationConfigApplicationContext 则是包含了注解解析等⼀系列的内容。Spring IoC 容器继承体系⾮常聪明,需要使⽤哪个层次⽤哪个层次即可,不必使⽤功能⼤⽽全的。
在这里插入图片描述
在idea中想要查看某个类或者接口的层级关系十分简单,只需要选中类ctrl+alt+u就能显示,比如ClassPathXmlApplicationContext ,从下图中我们可以看出他并不只是继承或者实现某一个接口或者类,这就验证了Spring IoC 容器继承体系⾮常聪明,我们不需要使用全而强大的全功能,而是将所有功能按照某规则分出来,需要什么就继承什么,大大减少使用的难度。
在这里插入图片描述

2.Bean⽣命周期关键时机点

通过之前我们在导入源码时写的测试类,开始断点调试。通过下面的调用栈 我们就可以分析出程序的执行流程。最关键的就是refresh()这个方法。
在这里插入图片描述

三、IOC总流程分析

在这里插入图片描述

@Override
	public void refresh() throws BeansException, IllegalStateException {
		// 对象锁加锁 Object startupShutdownMonitor = new Object()
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			/*刷新之前的预处理
			表示在真正做refresh操作之前需要准备的事情
			设置Spring容器的启动时间
			开启活跃状态 撤销关闭状态
			验证环境信息里一些必须存在的属性等*/
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 获取BeanFactory :默认实现是 DefaultListableBeanFactory
			// 加载BeanDefition 并注册到 BeanDefitionRegistry
			// 关键步骤
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// BeanFactory的预准备工作(前置处理)(BeanFactory进行设置 比如context的类加载器等)
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// BeanFactory的准备工作完成之后 进行的后置处理工作
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// 实例化实现了BeanFactoryPostProcessor接口的bean,并调用接口方法
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 注册BeanPostProcessor(bean的后置处理),在创建bean的前后等执行
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// 初始化MessageSource组件(做国际化功能:消息绑定和消息解析)
				initMessageSource();

				// Initialize event multicaster for this context.
				// 初始化事件派发器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 子类重写这个方法,在容器刷新的时候可以自定义逻辑:如创建tomcat jetty等web服务器
				onRefresh();

				// Check for listener beans and register them.
				// 注册应用的监听器。就是注册实现了ApplicationListener接口的监听器bean
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 初始化所有剩下的非懒加载的单例bean
				// 初始化创建非懒加载方式的单例bean的实例(属性未设置)
				// 填充属性
				// 初始化方法调用(比如调用afterPropertiesSet方法,init-method方法)
				// 调用beanPostProcessor(后置处理器)对实例bean进行后置处理
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// 完成context的刷新。主要调用LifecycleProcessor的onRefresh()方法,并且发布事件(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.
				destroyBeans();

				// Reset 'active' flag.
				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 容器初始化最重要的方法就是 refresh() 方法是所有的入口方法。然后就是刷新之前的预处理,比如设置容器启动时间,活跃状态等等,然后就是BeanFacotry的注册,初始化,后置处理等等,在到bean的初始化 前后置处理和将初始化的bean放入SingletonObjects池中。后续会详细解析beanFactory的初始化和bean的初始化和如何通过三级缓存来解决单例通过set注入的bean的循环依赖问题!

文章源码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

起风了 收衣服

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

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

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

打赏作者

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

抵扣说明:

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

余额充值