前言
Spring框架为什么如此流行?
原来Spring框架解决了一个很关键的问题,它可以把对象之间的依赖关系转为用配置文件来管理,也就是它的依赖注入机制。IOC容器用来管理这些Bean,管理Bean的关系以及生命周期,然而这与之前将应用程序主动new对象不同,Spring实现使用IOC容器创建对象,对象的获取方式反转了,所以IOC容器也称为控制反转。面对繁琐的依赖关系,我们不用一个一个去new对象,直接使用IOC创建好的对象,这也正是IOC的方便之处。
Spring 核心组件
Bean
Bean组件在org.springframework.beans包下,这个包下所有的类解决了Bean的定义,创建以及解析。
1.Bean的定义:主要有BeanDefinition描述,也可以说Spring中的Bean就是BeanDefinition的实例。Spring成功解析一个<bean/>节点后,在Spring的内部它就被转化为BeanDefinition对象。

2.Bean的创建:.Spring Bean的创建是典型的工厂设计模式,顶级接口是BeanFactory

3.Bean的解析:Bean的解析主要是对配置文件的解析

Context
context组件在org.framework.context包下,主要就是Bean关系的集合。给Spring提供了一个运行时环境用于存储对象的状态。ApplicationContext是顶级的父类

ApplicationContext继承了BeanFactory说明了Spring容器运行的主要对象是Bean
ApplicationContext实现了ResourceLoader接口说明ApplicationContext可以访问到外部资源。
Core
core组件就是发现,建立和维护每个Bean之间关系所需要的一系列工具。core组件其中一个重要的组成部分就是定义了资源的访问方式。

IOC的工作原理
下面我们看看IOC是怎样工作的呢?
先来一个小demo
MessageService.java
public interface MessageService {
String getMessage();
}
MessageServiceImpl.java
public class MessageServiceImpl implements MessageService {
public String getMessage() {
return "hello world";
}
}
application.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">
<bean id="messageService" class="com.kristin.spring.ioc.MessageServiceImpl"/>
</beans>
TestMessage.java
public class TestMessage {
public static void main(String[] args) {
// 用我们的配置文件来启动一个 ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
System.out.println("context 启动成功");
// 从 context 中取出我们的 Bean,而不是用 new MessageServiceImpl() 这种方式
MessageService messageService = context.getBean(MessageService.class);
// 这句将输出: hello world
System.out.println(messageService.getMessage());
}
}
运行结果:

IOC运行分析
从上面代码可以发现,IOC的入口就是ClassPathXmlApplicationContext的构造方法,下面我们看看源码是怎样写的
ClassPathXmlApplicationContext.java
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations); //根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
if (refresh) {
refresh(); //这里是核心代码
}
}
下面我们看一下refresh()
ClassPathXmlApplicationContext.java
@Override
public void refresh() throws BeansException, IllegalStateException {
//这里加锁,防止多个线程同时refresh()时出现问题
synchronized (this.startupShutdownMonitor) {
// 为刷新准备新的context,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
prepareRefresh();
// 刷新所有BeanFactory的子容器
// 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
// 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
// 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备BeanFactory,设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);
try {
// 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
// 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
postProcessBeanFactory(beanFactory);
// 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
// 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
registerBeanPostProcessors(beanFactory);
// 初始化message source
initMessageSource();
// 初始化 event multicaster
initApplicationEventMulticaster();
// 刷新由子类实现的方法
onRefresh();
// 注册事件监听器,监听器需要实现 ApplicationListener 接口。
registerListeners();
// 初始化所有的 singleton beans
finishBeanFactoryInitialization(beanFactory);
// 最后,广播事件,ApplicationContext 初始化完成
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();
}
}
}
refresh函数主要包含了以下几个步骤:
1.构建BeanFactory,以便于产生所需的"演员"
2.注册可能感兴趣的事件
3.创建Bean实例对象
4.触发被监听的事件
创建BeanFactory的时序图:

继续看一看refresh()函数中调用的函数吧
AbstractApplicationContext.java
protected void prepareRefresh() {
// 记录启动时间,将 active 属性设置为 true,closed 属性设置为 false,它们都是 AtomicBoolean 类型
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
initPropertySources();
// 校验 xml 配置文件
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
AbstractApplicationContext.java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean 等等
refreshBeanFactory();
// 返回刚刚创建的 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
AbstractRefreshableApplicationContext.java
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果 ApplicationContext 中已经加载过 BeanFactory 了,销毁所有 Bean,关闭 BeanFactory
// 注意,应用中BeanFactory本来就是可以多个的,这里可不是说应用全局是否有 BeanFactory,而是当前ApplicationContext是否有BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 初始化一个 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 用于 BeanFactory 的序列化
beanFactory.setSerializationId(getId());
// 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
customizeBeanFactory(beanFactory);
// 加载 Bean 到 BeanFactory 中,这个方法很重要
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
此时已经获得了BeanFactory
后面会陆续更新,暂时先整理到这里...
参考:
https://javadoop.com/post/spring-ioc
《深入分析Java Web技术内幕》