Spring IoC容器的体系结构(初涉)

本贴最后更新于 2797 天前,其中的信息可能已经时移世改

1. 依赖注入(Dependency Injection)和控制反转(Inversion of Control)(待补充)

"The question is, what aspect of control are [they] inverting?" Martin Fowler posed this question about Inversion of Control (IoC) on his site in 2004.

2. Spring IoC 容器的体系结构

在 Spring 中,最顶层的 IoC 容器接口是 BeanFactory。它定义了 IoC 容器的基本功能规范,但不关心你的 bean 是如何定义怎样加载的。正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口一点都不关心。且看它的规范:

public interface BeanFactory {    
 
    //对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,    
    //如果需要得到工厂本身,需要转义           
    String FACTORY_BEAN_PREFIX = "&"; 
    
    //根据bean的名字,获取在IOC容器中得到bean实例    
    Object getBean(String name) throws BeansException;    

    //根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。    
    Object getBean(String name, Class requiredType) throws BeansException;    

	//提供对bean的检索,看看是否在IOC容器有这个名字的bean    
 	boolean containsBean(String name);    

	//根据bean名字得到bean实例,并同时判断这个bean是不是单例    
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;    

	//得到bean实例的Class类型    
	Class getType(String name) throws NoSuchBeanDefinitionException;    

	//得到bean的别名,如果根据别名检索,那么其原名也会被检索出来    
	String[] getAliases(String name);    

 } 

BeanFactory 有三个子类:ListableBeanFactoryHierarchicalBeanFactoryAutowireCapableBeanFactory。那为何要定义这么多的子接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它们主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为。最终 Spring 中默认提供的集结了它们所有特性的 IoC 容器是 DefaultListableBeanFactory。它的 UML 结构图如下:
DefaultListableBeanFactory

如果说 BeanFactory 是个屌丝容器规范,那么 ApplicationContext 就是个高富帅容器规范。它除了能够提供 IoC 容器的基本功能外,还增加了国际化事件的传播资源的加载,和透明地创建上下文等附加服务。且看它的 UML 结构:
ApplicationContext

3. Spring IoC 容器的初始化过程

ApplicationContext 的一个标准实现 ClassPathXmlApplicationContext 作为分析案列。当执行

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(FQ_SIMPLE_CONTEXT);

跟进代码发现最终执行的构造函数里做了三件事

/**
 * Create a new ClassPathXmlApplicationContext with the given parent,
 * loading the definitions from the given XML files.
 * @param configLocations array of resource locations
 * @param refresh whether to automatically refresh the context,
 * loading all bean definitions and creating all singletons.
 * Alternatively, call refresh manually after further configuring the context.
 * @param parent the parent context
 * @throws BeansException if context creation failed
 * @see #refresh()
 */
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
		throws BeansException {
    
    // 初始化基类
    // 在初始化`AbstractApplicationContext`时,设置资源匹配解析器(`resourcePatternResolver`)为`PathMatchingResourcePatternResolver`
    super(parent);

    // 1. 设置资源的配置路径
    setConfigLocations(configLocations);

    // 2. 刷新容器,未启动状态即启动容器
    if (refresh) {
        refresh();
    }
}

方法的注释写的很清楚:

  1. 使用给定的父对象创建新的 ClassPathXmlApplicationContext
  2. 从给定的 XML 文件配置里加载所有 Bean 的定义信息并为之创建单例对象
  3. 配置完上下文后手动刷新(启动)容器

这个方法相对比较简单,而定义在 AbstractApplicationContextrefresh() 方法,它是个模板方法,规范了容器启动的步骤,代码如下

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 1. 为启动容器做准备
		// Prepare this context for refreshing
		prepareRefresh();

		// 2. 告诉子类去刷新内部的bean工厂
		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// 3. 准备bean工厂在上下文的使用
		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// 4. 允许bean工厂在上下文中的子类进行后处理
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// 5. 调用以bean形式注册在上下文里的工厂处理器
			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// 6. 注册拦截bean创建的bean处理器
			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			// 7. 初始化上下文的消息资源(国际化)
			// Initialize message source for this context.
			initMessageSource();

			// 8. 初始化上下文的事件广播器
			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// 9. 初始化上下文里指定子类其他指定的bean
			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// 10. 检查事件监听器并注册
			// Check for listener beans and register them.
			registerListeners();

			// 11. 初始化剩余的(非延迟加载)单例Beans
			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// 12. 发布一致的事件
			// Last step: publish corresponding event.
			finishRefresh();
		}
		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// 1. 销毁已经创建的单例避免资源的挂起
			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// 2. 重置“激活”状态
			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}
		finally {
			// 当我们可能不再为单例Beans需要元数据时,重置在Spring Core模块中通用内省的缓存
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}
  • Spring

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

    941 引用 • 1458 回帖 • 150 关注
  • IoC
    17 引用 • 29 回帖

相关帖子

欢迎来到这里!

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

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