spring ioc 原理


Spring IOC容器实现与源码分析

1、IOC位置

  • 核心容器包括spring-core、spring-beans、spring-context、spring-context-support、spring-expression,其中spring-core、spring-bean模块提供整个框架的基本功能,包含了IOC和依赖注入特性。本文也主要结合源码分析该部分,来看IOC设计的思想。

  • 从该图可以体现分层架构思想。

2、 如何阅读源码

  • 带着问题思考阅读IOC容器源码
    • 1、IOC容器解决什么问题?自己如何实现IOC,有哪些难点?
    • 2、IOC容器如何管理依赖注入的对象
    • 3、核心数据结构
    • 4、如何加载Bean的定义的,如何解析的
    • 5、两个Bean在不同的XML里,如何做解析的
    • 6、XML配置的Bean,依赖注入的Bean是通过注解初始化化的,又是如何解决依赖的
    • 7、如何考虑扩展性,如何对Bean的不同应用场景进行扩展
    • 8、IOC的构成体系、设计体系、主要思想是什么?
    • 9、BeanFactory如何考虑GC的?
    • 10、BeanFactory与FactoryBean区别?

3、设计与实现

3.1、工作流程

3.2、接口概况

3.2.1、容器接口

3.2.2、Context继承关系

3.2.3、Bean定义类图

3.2.4、Bean解析类图

3.3 接口设计理解

3.3.1 BeanFactory方法概览

public interface BeanFactory {

	String FACTORY_BEAN_PREFIX = "&";

	Object getBean(String name) throws BeansException;

	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	<T> T getBean(Class<T> requiredType) throws BeansException;

	Object getBean(String name, Object... args) throws BeansException;

	boolean containsBean(String name);

	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
	
	boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;

	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	String[] getAliases(String name);
}

3.3.2 基础容器

  • 从BeanFactory—>HierarchicalBeanFactory—>ConfigurableBeanFactory该设计是容器的基础功能,也是容器的标准实现的规范。BeanFactory提供getBean基本方法,HierarchicalBeanFactory增加了getParentBeanFactory获取父工厂方法,联想Java的类加载机制,这不是双亲委派么?ConfigurableBeanFactory提供了容器的配置功能,如setParentBeanFactory设置双亲委派,addBeanPostProcessor添加后置处理器等。
  • HierarchicalBeanFactory为什么只有设置父容器方法?

3.3.3 高级容器

  • 从BeanFactory—>ListableBeanFactory—->ApplicationContext为一条设计路线,该设计主要是面对开发者使用,屏蔽底层基础容器的实现。ListableBeanFactory提供可返回管理对列表的能力,ApplicationContex同时实现了资源加载、国际化、事件监听机制等高级特性

3.4 主要思想

源码学习的目的在于学习借鉴别人的设计思路,使自己的思路开阔与升华,通过学习总结以下相关思想观点

  • 依赖注入,通过配置文件和注解的方式来解决该问题
  • 工厂模式
  • 模板模式
  • 分层设计
  • 单一职责
  • Spring IOC容器表现形式为BeanFactory与ApplicationContext,前者是最基本的容器,提供基础功能,后者是容器的高级形态,提供应用环境的适配与高级功能

4、源码分析

4.1 Bean加载深度分析

4.1.1、构造方法

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
                throws BeansException {
            super(parent);
            setConfigLocations(configLocations);
            if (refresh) {
                refresh();
            }
        }
  • 构造参数:
    • 1、资源数组路径
    • 2、是否刷新上下文
    • 3、父上下文对象
  • 构造方法工作:
    • 1、初始化资源解析器
    • 2、设置资源信息
    • 3、解析刷新上下文(核心流程)

4.1.2、Refresh源码

refresh是AbstractApplicationContext的方法,该抽象类定义了IOC容器的一系列基础方法与抽象方法(模板设计模式),refresh定义了加载与初始化的流程。可以看到该方法内部有synchronized,主要是避免多线程同时刷新上下文,不是加在整个方法体而是对象startupShutdownMonitor上呢?该方法设计的流程清晰

    	synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
		}
4.1.2.1 obtainFreshBeanFactory方法

obtainFreshBeanFactory用来刷新Spring工厂的上下文,代码如下

    	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}
  • 其中refreshBeanFactory是核心实现,该方法是抽象方法又两个子类分别进行了实现AbstractRefreshableApplicationContext和GenericApplicationContext,从上面的时序图得知目前调用的AbstractRefreshableApplicationContext的实现,代码如下
    protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(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);
		}
	}
  • 此方法有两个核心实现一个是创建DefaultListableBeanFactory,一个是loadBeanDefinitions加载Bean的定义,内部的核心

4.2 主要流程总结

  • 1、IOC容器主要以下几个阶段:
    • 1)、bean的定义阶段
    • 2)、bean的解析阶段
    • 3)、bean的实例化阶段
    • 4)、使用Bean阶段
  • 2、Bean的定义阶段主要经历几个步骤:
    • 1)读取资源文件存放到一个数组里面
    • 2)初始化xmlreder器
    • 3)装载bean定义文件
    • 4)通过流读入资源文件转换为docment对象
    • 5)注册Bean定义,也就是真正解析XML,分为解析默认和解析自定义
  • 3、双亲委派的意义,应用场景? 回顾类加载的双亲委派机制,每个加载器加载相应的class对象,避免多次加载同一个对象,减少内存开销(类A中使用了List,类B也会使用List,都各自加载各自的就悲剧了)。同样如此Bean对象之间会相互依赖同一个对象。


Comments