Spring IOC 过程源码解析

本贴最后更新于 1930 天前,其中的信息可能已经东海扬尘

废话不多说,我们先做一个傻瓜版的 IOC demo 作为例子

自定义的 Bean 定义

class MyBeanDefinition{

    public String id;
    public String className;
    public String value;

    public MyBeanDefinition(String id, String className, String value) {
        this.id = id;
        this.className = className;
        this.value = value;
    }

}

自定义的 Bean 工厂


class MyBeanFactory {

    Map<String, Object> beanMap = new HashMap<>();

    public MyBeanFactory(MyBeanDefinition beanDefinition) throws ClassNotFoundException,
            IllegalAccessException, InstantiationException {

        Class<?> beanClass = Class.forName(beanDefinition.className);
        Object bean = beanClass.newInstance();
        ((UserService) bean).setName(beanDefinition.value);
        beanMap.put(beanDefinition.id, bean);

    }

    public Object getBean(String id) {
        return beanMap.get(id);
    }


}

测试傻瓜版 IOC 容器

public class EasyIOC {

    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {

        MyBeanDefinition beanDefinition = new MyBeanDefinition("userService",
                "com.valarchie.UserService", "archie");

        MyBeanFactory beanFactory = new MyBeanFactory(beanDefinition);
        UserService userService = (UserService) beanFactory.getBean("userService");

        System.out.println(userService.getName());

    }


}

看完以上这个傻瓜版的例子我们可以思考一下?让我们自己实现 IOC 的容器的关键是什么呢?

按照我的理解,我总结为以下三步

  • 读取 xml 文件形成 DOM 对象
  • 读取 DOM 文档对象里的 Bean 定义并装载进 BeanFactory 中
  • 根据 bean 定义生成实例放进容器,以供使用

所以,接下来我们不会通盘分析整个 IOC 的流程,因为旁枝细节太多读者看完也云里雾里抓不到重点。
我们通过分析最重要的这条代码主干线来理解 IOC 的过程。

开始分析:

首先我们从 xml 的配置方式开始分析,因为 Spring 最初的配置方式就是利用 xml 来进行配置,所以大部分人对 xml 的配置形式较为熟悉,也比较方便理解。

从 ClassPathXmlApplicationContext 的构造器开始讲起。

public class TestSpring {
    public static void main(String[] args) {
        // IOC容器的启动就从ClassPathXmlApplicationContext的构造方法开始
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
        UserService userService = (UserService) context.getBean("userService");
        System.out.println(userService.getName());
       
    }
}

进入到构造方法中,调用重载的另一个构造方法。

// 创建ClassPathXmlApplicationContext,加载给定的位置的xml文件,并自动刷新context
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
}

重载的构造方法中,由于刚才 parrent 参数传为 null,所以不设置父容器。refresh 刚才设置为 true,流程就会进入 refresh()方法中

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {
        // 由于之前的方法调用将parent设置为null,所以我们就不分析了
		super(parent);
		// 设置路径数组,并依次对配置路径进行简单占位符替换处理,比较简单,我们也不进入分析了
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
}

整个 refresh()方法中就是 IOC 容器启动的主干脉络了,Spring 采用了模板方法设计模式进行 refresh()方法的设计,先规定好整个 IOC 容器的具体步骤,然后将每一个小步骤由各种不同的子类自己实现。

所有重要的操作都是围绕着 BeanFactory 在进行。
在注释当中,我们详细的列出了每一步方法所完成的事情。ApplicationContext 内部持有了 FactoryBean 的实例。其实 ApplicationContext 本身最上层的父接口也是 BeanFactory,他拓展了 BeanFactory 之外的功能(提供国际化的消息访问、资源访问,如 URL 和文件、事件传播、载入多个(有继承关系)上下文)

我们先通过阅读代码中的注释来了解大概的脉络。

public void refresh() throws BeansException, IllegalStateException {
        // 先加锁防止启动、结束冲突
		synchronized (this.startupShutdownMonitor) {
			// 在刷新之前做一些准备工作
			// 设置启动的时间、相关状态的标志位(活动、关闭)、初始化占位符属性源,并确认
			// 每个标记为必须的属性都是可解析的。
			prepareRefresh();

			// 获取一个已刷新的BeanFactory实例。
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 定义好Bean工厂的环境特性,例如类加载器,或者后置处理器
			prepareBeanFactory(beanFactory);

			try {
				// 设置在BeanFactory完成初始化之后做一些后置操作,spring留给子类的扩展。
				postProcessBeanFactory(beanFactory);

				// 启动之前已设置的BeanFactory后置处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册Bean处理器
				registerBeanPostProcessors(beanFactory);

				// 为我们的应用上下文设置消息源(i18n)
				initMessageSource();

				// 初始化事件广播器
				initApplicationEventMulticaster();

				// 初始化特殊的Bean在特殊的Context中,默认实现为空,交给各个具体子类实现
				onRefresh();

				// 检查监听器并注册
				registerListeners();

				// 实例化所有非懒加载的Bean
				finishBeanFactoryInitialization(beanFactory);

				// 最后一步发布相应的事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 如果启动失败的话,要销毁之前创建的Beans。
				destroyBeans();

				// 重置ApplicationContext内部active的标志位
				cancelRefresh(ex);

				// 向调用者抛出异常
				throw ex;
			}

			finally {
			    // 重置Spring核心内的缓存,因为我们可能不再需要单例bean相关的元数据
				resetCommonCaches();
			}
		}
	}

阅读完之后我们重点关注 obtainFreshBeanFactory()、finishBeanFactoryInitialization(beanFactory)这两个方法,因为实质上整个 IOC 的流程都在这两个方法当中,其他的方法一部分是 Spring 预留给用户的自定义操作如 BeanFactory 的后置处理器和 Bean 后置处理器,一部分是关键启动事件的发布和监听操作,一部分是关于 AOP 的操作。

首先,先从 obtainFreshBeanFactory()开始说起。

第一步:读取 xml 文件形成 DOM 对象

在 getBeanFactory()方法之前,先调用 refreshBeanFactory()方法进行刷新。我们先说明一下,getBeanFactory()非常简单,默认实现只是将上一步刷新成功好构建好的 Bean 工厂进行返回。返回出去的 Bean 工厂已经加载好 Bean 定义了。所以在 refreshBeanFactory()这个方法中已经包含了第一步读取 xml 文件构建 DOM 对象和第二步解析 DOM 中的元素生成 Bean 定义进行保存。记住,这里仅仅是保存好 Bean 定义,此时并未涉及 Bean 的实例化。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
}

进入 refreshBeanFactory()方法中

此时我们的 xml 文件已经加载并解析成 DOM 结构对象了,第一步已经完成了。

第二步:读取 DOM 文档对象里的 Bean 定义并装载进 BeanFactory 中

// 内部核心代码就这两句
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
		

我们再回到刚刚讲到的这两句核心代码,第一句获取 DOM 对象后,紧接着第二句 registerBeanDefinitions(doc, resource)开始了 bean 定义的注册工作。

进入 registerBeanDefinitions(doc, resource)方法中

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // 生成DOM读取器,这个和刚才的读取器不一样,之前的读取器是xml读取器。
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// 获取之前的bean定义数量 
		int countBefore = getRegistry().getBeanDefinitionCount();
		
		// 进入重点
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		
		// 用刚刚又创建的bean定义数量 - 之前的bean定义数量 = 刚刚一共创建的bean定义 
		return getRegistry().getBeanDefinitionCount() - countBefore;
}

进入 documentReader.registerBeanDefinitions(doc, createReaderContext(resource))方法。
方法内读取文档的 root 元素。

解析成功后将 Bean 定义进行保存。第二步也已经完成。

第三步:使用创建好的 Bean 定义,开始实例化 Bean。

我们回到最开始的 refresh 方法中,在 finishBeanFactoryInitialization(beanFactory)方法中,开始实例化非懒加载的 Bean 对象。我们跟着调用链进入到 preInstantiateSingletons()方法中

@Override
public void preInstantiateSingletons() throws BeansException {
	if (this.logger.isDebugEnabled()) {
		this.logger.debug("Pre-instantiating singletons in " + this);
	}

	// 将之前做好的bean定义名列表拷贝放进beanNames中,然后开始遍历
	List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

	// 触发所有非懒加载的单例Bean实例化
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		
		// 如果非抽象并且是单例和非懒加载的话
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
		    // 检测是否是工厂方法Bean。 创建Bean的不同方式,读者可自行百度。
			if (isFactoryBean(beanName)) {
				final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
				boolean isEagerInit;
				if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
					isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
						@Override
						public Boolean run() {
							return ((SmartFactoryBean<?>) factory).isEagerInit();
						}
					}, getAccessControlContext());
				}
				else {
					isEagerInit = (factory instanceof SmartFactoryBean &&
							((SmartFactoryBean<?>) factory).isEagerInit());
				}
				if (isEagerInit) {
					getBean(beanName);
				}
			}
			else {
				getBean(beanName);
			}
		}
	}

    // 关于实例化之后做的自定义操作代码省略....
}

在该方法中根据 Bean 实例是通过工厂方法实例还是普通实例化,最主要的方法还是 getBean(beanName)方法。我们继续分析普通实例化的过程。进入 getBean()方法当中 doGetBean()方法,发现方法参数 doGetBean(name, null, null, false)后三个参数全部为 null,它就是整个 IOC 中的核心代码。

代码中先通过实例化 Bean,实例化好之后再判断该 Bean 所需的依赖,并递归调用进行实例化 bean,成功后整个 IOC 的核心流程也就完成了。

protected <T> T doGetBean(
		final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
		throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

	// 从缓存中获取beanName对应的单例
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		if (logger.isDebugEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		// 返回beanName对应的实例对象(主要用于FactoryBean的特殊处理,
		// 普通Bean会直接返回sharedInstance本身)
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	else {
	    // scope为prototype的循环依赖校验:如果beanName已经正在创建Bean实
	    // 例中,而此时我们又要再一次创建beanName的实例,则代表出现了循环
	    // 依赖,需要抛出异常。
            // 例子:如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候
            //,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成
            //循环依赖
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

    	//如果parentBeanFactory存在,并且beanName在当前BeanFactory不存在
    	//Bean定义,则尝试从parentBeanFactory中获取bean实例
		BeanFactory parentBeanFactory = getParentBeanFactory();
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// 将别名解析成真正的beanName
			String nameToLookup = originalBeanName(name);
			if (args != null) {
				// Delegation to parent with explicit args.
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else {
				// No args -> delegate to standard getBean method.
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
		}

        // 如果不需要类型检查的话 标记为已创建
		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}

		try {
		    // 将子Bean定义与父Bean定义进行整合
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			// 整合后如果发现是抽象类不能实例 抛出异常
			checkMergedBeanDefinition(mbd, beanName, args);

			// 获取Bean定义所需的依赖并逐一初始化填充
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (String dep : dependsOn) {
				    // 判断是否循环依赖
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					// 注册依赖的Bean
					registerDependentBean(dep, beanName);
					try {
					// 递归调用生成所需依赖的Bean
						getBean(dep);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}

			// 如果是单例的话
			if (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
					@Override
					public Object getObject() throws BeansException {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}

            // 如果是原型的话
			else if (mbd.isPrototype()) {
				// It's a prototype -> create a new instance.
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}
            		// 非单例和原型 范围的情况 例如session,request等情况
			else {
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				try {
					Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						}
					});
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				}
				catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName,
							"Scope '" + scopeName + "' is not active for the current thread; consider " +
							"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
							ex);
				}
			}
		}
		catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throw ex;
		}
	}

	// 检测实例Bean的类型和所需类型是否一致
	if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
		try {
			return getTypeConverter().convertIfNecessary(bean, requiredType);
		}
		catch (TypeMismatchException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to convert bean '" + name + "' to required type '" +
						ClassUtils.getQualifiedName(requiredType) + "'", ex);
			}
			throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
		}
	}
	return (T) bean;
}

根据 Bean 定义去实例化 Bean。第三步也已经完成。

文章篇幅有限,IOC 整个的创建过程还是比较冗长的,希望读者看完文章对 IOC 的创建过程有一个主干脉络的思路之后还是需要翻开源码进行解读,其实阅读源码并不难,因为 Spring 的代码注释都挺健全,如果遇到不清楚的稍微 google 一下就知道了。建议读者自己试着一步一步的分析 IOC 过程的源码。

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    943 引用 • 1460 回帖 • 3 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...