Spring源码阅读----Spring IoC之BeanFactory、ApplicationContext

概述

Spring Framework

前面我们通过一个SSMdemo熟悉了一下Spring的工作环境。IOC是Spring框架的一个重要特性,实现IOC的关键是bean,而更关键的是如何bean的管理容器,也就是BeanFactory,现在我们开始从容器模块解读源码。

BeanFactory

我们先通过一个示例来看看BeanFactory如何工作的:

在前面的最后有个例子通过ClassPathXmlApplicationContext解析配置文件,并获取bean。

    public static void main(String[] args) throws ClassNotFoundException {
        //XmlBeanFactory已经被废弃
        //XmlBeanFactory使用方式如下:
        //BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        //这里使用了ClassPathXmlApplicationContext
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");

        SysAdminUserService s = (SysAdminUserService)context.getBean(SysAdminUserService.class);

        List<SysAdminUser> list = s.selectAll(new SysAdminUser());
        list.stream().forEach(System.out::println);
    }

先来查看XmlBeanFactory的类图,如下:

XmlBeanFactory

再查看ClassPathXmlApplicationContext的类图,如下:

ClassPathXmlApplicationContext
从中可以看到XmlBeanFactory、ClassPathXmlApplicationContext的父类实现的接口中,最顶层都是BeanFactory。

BeanFacotry,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂,在spring-beans包中,它是IOC容器的核心接口,是Spring里面最底层的接口,提供了最简单的容器的功能。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。BeanFactory在启动的时候不会去实例化Bean,有从容器中拿Bean的时候才会去实例化

ApplicationContext接口,应用上下文,在spring-context包中,也是一个IOC容器,比BeanFacotry更高级,它由BeanFactory接口派生而来。ApplicationContext包含BeanFactory的所有功能,并提供了更多其他有用的功能,通常建议使用ApplicationContext优先于BeanFactory。ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化。ClassPathXmlApplicationContext类就是其中一个实现ApplicationContext接口的类,类似的类比较常用的还有AnnotationConfigApplicationContext类,前者是根据xml配置文件启动,后者则根据注解配置启动。

我们先看XmlBeanFactory的加载方式,更多的会聚焦和ApplicationContext接口相关的类。
demo源码

//通过XmlBeanFactory来创建BeanFactory 实例
BeanFactory factory = new XmlBeanFactory(
			new ClassPathResource("applicationContext.xml"));

执行结果如下:

factory

跟踪源码进入XmlBeanFactory类

@Deprecated
public class XmlBeanFactory extends DefaultListableBeanFactory {
    private final XmlBeanDefinitionReader reader;

    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, (BeanFactory)null);
    }

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader = new XmlBeanDefinitionReader(this);
        //loadBeanDefinitions
        this.reader.loadBeanDefinitions(resource);
    }
}

可以看到在XmlBeanFactory的构造方法中,创建了XmlBeanDefinitionReader对象,并调用了loadBeanDefinitions方法,其具体源码如下

//XmlBeanDefinitionReader中

	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Loading XML bean definitions from " + encodedResource);
		}

		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
			// 从资源文件中获取输入流
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				//doLoadBeanDefinitions
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

从上面源码中,我们继续跟踪doLoadBeanDefinitions方法

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			//将资源文件解析成 document
			Document doc = doLoadDocument(inputSource, resource);
			// 从 doc 和资源中解析元素,注册到 bean factory
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (SAXParseException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
		}
		catch (SAXException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"XML document from " + resource + " is invalid", ex);
		}
		catch (ParserConfigurationException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Parser configuration exception parsing XML from " + resource, ex);
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"IOException parsing XML document from " + resource, ex);
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Unexpected exception parsing XML document from " + resource, ex);
		}
	}

我们主要看核心部分:registerBeanDefinitions方法


	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	
		// 使用 DefaultBeanDefinitionDocumentReader 实例化 BeanDefinitionDocumentReader
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		
		// 记录统计前 beanDefinition 的加载个数
		int countBefore = getRegistry().getBeanDefinitionCount();
		
		// 执行registerBeanDefinitions,加载及注册 bean,这里使用注册工厂的是 DefaultListableBeanFactory
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		
		// 记录本次加载的 BeanDefinition 个数(新值 - 旧值)
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

查看DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法:


	@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		
        //获取Document的root元素,即配置文件中的<beans>标签
        //然后执行doRegisterBeanDefinitions方法
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}

    //执行doRegisterBeanDefinitions
	protected void doRegisterBeanDefinitions(Element root) {
		// 委托给BeanDefinitionParserDelegate对象来处理bean的解析
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		if (this.delegate.isDefaultNamespace(root)) {
		
			//处理<beans>标签中的profile属性
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				// We cannot use Profiles.of(...) since profile expressions are not supported
				// in XML config. See SPR-12458 for details.
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isDebugEnabled()) {
						logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}
		// preProcess 和 postProcess 点进去会发现是空方法,这两个方法留给子类重载,体现了设计模式 - 模板方法
		preProcessXml(root);
		// 注释1 核心方法,解析 doc 元素,主要看这步Bean的解析
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}

从上面的代码继续追踪parseBeanDefinitions方法,此方法来解析beans标签的方法

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            //获取<beans>标签的子节点如<bean>、<context:component-scan>、<import>等等
            NodeList nl = root.getChildNodes();

            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element)node;
                    //默认命名空间的标签
                    if (delegate.isDefaultNamespace(ele)) {
                        //解析默认标签
                        this.parseDefaultElement(ele, delegate);
                    } else {
                        //自定义命名空间的标签
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            //自定义命名空间的标签
            delegate.parseCustomElement(root);
        }

    }

这里遍历root节点标签下的子节点,用命名空间来区分解析各节点元素。
默认命名空间在BeanDefinitionParserDelegate类中定义了,如下:

public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";

像、就是默认的命名空间,tx:annotation-driven就是自定义的命名空间

    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations" value="classpath:jdbc.properties"/>
    </bean>

<import resource="classpath:spring-mybatis.xml" />

那我们继续追踪解析默认命名空间中标签的parseDefaultElement方法

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
        } else if (delegate.nodeNameEquals(ele, "alias")) {
            this.processAliasRegistration(ele);
        } else if (delegate.nodeNameEquals(ele, "bean")) {
            //这里解析<bean>标签的方法
            this.processBeanDefinition(ele, delegate);
        } else if (delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);
        }

    }

    //processBeanDefinition 处理加工BeanDefinition
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //①这里委托给BeanDefinitionParserDelegate对象来解析Bean标签
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
                //②核心-注册BeanDefinition
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }

            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }

我们先追踪上面①部分,BeanDefinitionParserDelegate类中的parseBeanDefinitionElement方法,看它是如何解析标签的:

//BeanDefinitionParserDelegate类中
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		// 获取 ID 属性
		String id = ele.getAttribute(ID_ATTRIBUTE);
		// 获取 NAME 属性
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			// 名称按照 , ; 进行分割
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			// 如果没有指定 id,将 name 的第一个值作为 id
			beanName = aliases.remove(0);
			if (logger.isTraceEnabled()) {
				logger.trace("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}
		// 默认 null
		if (containingBean == null) {
			// 检查名字是否唯一,如果 id 重复了,将抛出错误
			// 内部 usedNames 是一个 HashSet,将会存储加载过的 name 和 aliases
			checkNameUniqueness(beanName, aliases, ele);
		}

                //前边获取了bean的id、name等属性
                //这里才是核心解析方法:parseBeanDefinitionElement
		// 解析 bean 标签的其它属性
		// 将公共属性放入 AbstractBeanDefinition,具体实现在子类 GenericBeanDefinition
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						// 如果 id 和 name 都是空,那个 spring 会给它生成一个默认的名称
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
					if (logger.isTraceEnabled()) {
						logger.trace("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}
		return null;
	}

 //核心解析方法
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        String className = null;
        if (ele.hasAttribute("class")) {
            className = ele.getAttribute("class").trim();
        }

        String parent = null;
        if (ele.hasAttribute("parent")) {
            parent = ele.getAttribute("parent");
        }

        try {
            //通过BeanDefinitionReaderUtils类的createBeanDefinition方法可以看到创建的是GenericBeanDefinition对象
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            this.parseMetaElements(ele, bd);
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            this.parseConstructorArgElements(ele, bd);
            this.parsePropertyElements(ele, bd);
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
        } catch (ClassNotFoundException var13) {
            this.error("Bean class [" + className + "] not found", ele, var13);
        } catch (NoClassDefFoundError var14) {
            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
        } catch (Throwable var15) {
            this.error("Unexpected failure during bean definition parsing", ele, var15);
        } finally {
            this.parseState.pop();
        }

        return null;
    }

这里的步骤:
先获取标签的id、name属性。名称可能是多个使用逗号进行隔开的,相当于alias标签;
然后调用核心解析方法parseBeanDefinitionElement,获取AbstractBeanDefinition(GenericBeanDefinition)对象;
最后返回new BeanDeifinitionHolder,包含了BeanDefinition信息、bean名称、别名数组。

接下来我们追踪上边②部分,核心部分:注册BeanDefinition,调用了BeanDefinitionReaderUtils类中的registerBeanDefinition方法:

	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Register bean definition under primary name.
		// 注释 在 DefaultListableBeanFactory 的 beanDefinitionMap 中添加 bean 定义
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}

小结一下

这里通过XmlBeanFactory来创建BeanFactory 实例的过程,就是通过XmlBeanFactory构造方法,开始解析XML配置文件,生成Docuemnt对象,解析Document中的标签,按标签的类型来进行分类解析,有些标签需要委托给BeanDefinitionParserDelegate对象解析,最后将BeanDefinition注册到DefaultListableBeanFactory的beanDefinitionMap中;或者SimpleAliasRegistry中的aliasMap。
不论是使用解析Xml还是使用ComponentScan等解析的BeanDefinition都需要进行注册,这样BeanFactory才能统一管理这些bean。

ApplicationContext

接下来我们解析一下ApplicationContext,这个接口的实现类非常多,不过不管是XmlWebApplicationContext、ClassPathXmlApplicationContext,还是AnnotationConfigApplicationContext,这些都是AbstractApplicationContext的派生类,模板方法refresh方法在该类中定义,核心逻辑也都是在 AbstractApplicationContext 抽象类中,另外还需要分析ConfigurableApplicationContext接口,它继承了ApplicationContext接口和Lifecycle接口(Spring容器的生命周期,比较简单的生命周期,定义了启动,停止、是否在运行中三个方法)。

demo中的代码如下:

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

执行结果如下:

context

跟踪源码进入ClassPathXmlApplicationContext的构造函数:

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[]{configLocation}, true, (ApplicationContext)null);
    }

    //调用核心方法
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) 
                                                                 throws BeansException {
        super(parent);
        //设置一下传入的xml配置文件路径,赋值给configLocations属性
        this.setConfigLocations(configLocations);
        if (refresh) {
            //核心方法:ApplicationContext初始化
            this.refresh();
        }
    }

先看一下setConfigLocation方法,跟踪源码发现它在AbstractRefreshableConfigApplicationContext类中,源码如下:

    public void setConfigLocation(String location) {
        this.setConfigLocations(StringUtils.tokenizeToStringArray(location, ",; \t\n"));
    }

    public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];

            for(int i = 0; i < locations.length; ++i) {
                //循环处理每个location字符串
                this.configLocations[i] = this.resolvePath(locations[i]).trim();
            }
        } else {
            this.configLocations = null;
        }
    }

    //处理ocation字符串的方法
    protected String resolvePath(String path) {
        //Spring容器的Environment在这里通过getEnvironment方法初始化
        //然后调用resolveRequiredPlaceholders方法处理字符串
        return this.getEnvironment().resolveRequiredPlaceholders(path);
    }

继续查看getEnvironment方法,它来自AbstractApplicationContext类:

    public ConfigurableEnvironment getEnvironment() {
        if (this.environment == null) {
            //创建一个StandardEnvironment对象
            this.environment = this.createEnvironment();
        }

        return this.environment;
    }

    protected ConfigurableEnvironment createEnvironment() {
        return new StandardEnvironment();
    }

这里我们获取了一个StandardEnvironment对象,StandardEnvironment类继承自AbstractEnvironment,在开发中可以获取很多环境信息,对项目执行时监控非常有帮助。
查看一下StandardEnvironment类关系图:

StandardEnvironment

可以看到它的父类实现了Enviroment、ConfigurablePropertyResolver接口,它们又继承了PropertyResolver接口。查看接口里的方法可以发现Enviroment跟Spring中各类 profiles处理有关、ConfigurablePropertyResolver跟Spring中的类型转换ConversionService有关、PropertyResolver接口跟Spring中的Property处理有关。
我们项目中经常会使用不同的运行环境,dev,test 或者 prod等,这个时候加载的配置文件和属性应该有所不同,这个时候就需要使用到 Environment 来进行区分。

我们需要了解Spring 环境和属性是由四个部分组成:

  • Environment : 环境
  • Profile : 配置文件,可以理解为,容器里多个配置组别的属性和 bean,只有激活的 profile,它对应的组别属性和 bean 才会被加载
  • PropertySource : 属性源
  • PropertyResolver : 属性解析器,这个用途就是解析属性

Profile 相信大家都很熟悉了,在springboot项目里我们会使用spring.profiles.active=dev来指定profile配置文件,Spring中原始的方式是在xml配置文件里设置,如下:

<!-- 测试环境配置文件 -->
<beans profile="test">
    <context:property-placeholder location="classpath:test/*.properties, classpath:common/*.properties" />
</beans>

<!-- 生产环境配置文件 -->
<beans profile="prod">
    <context:property-placeholder location="classpath:production/*.properties, classpath:common/*.properties" />
</beans>

<!-- 开发环境配置文件 -->
<beans profile="dev">
    <context:property-placeholder location="classpath:dev/*.properties, classpath:common/*.properties" />
</beans>

然后使用的时候可以使用以下两种方法:
①在 web.xml 中设置

<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev</param-value>
</context-param>

②直接在代码中设置

//容器初始化后
context.getEnvironment().setActiveProfiles("dev");

PropertySources
在StandardEnvironment类中我们可以看到customizePropertySources方法对PropertySources的操作

    protected void customizePropertySources(MutablePropertySources propertySources) {
        propertySources.addLast(new MapPropertySource("systemProperties", this.getSystemProperties()));
        propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
    }

MutablePropertySources 的底层是一个CopyOnWriteArrayList,容器初始化之后可以在代码中获取:

((MutablePropertySources)((StandardEnvironment)context.environment).propertySources).propertySourceList

好了,配置信息和环境的部分就讲解到这里。

回到上边,要开始refresh方法了,Bean 的解析和注册都在这里

在设置了配置信息之后,接下来就需要对ApplicationContext进行初始化操作了,也就是执行refresh方法,这个方法在AbstractApplicationContext类中实现:

//AbstractApplicationContext类中

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            // 1为更新准备上下文
            //对系统属性或者环境变量的校验,设定一些标志
            this.prepareRefresh();

            // 2告诉子类去更新它们的 bean factory
            //对xml配置的解析并注册bean到bean factory
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

            // 3对BeanFactory进行各种使用前的扩展准备
            this.prepareBeanFactory(beanFactory);

            try {
                // 模板方法,交给子类实现
                //允许子类对BeanFactory进行一些后期扩展
                this.postProcessBeanFactory(beanFactory);

                // 4 引用执行注册过的beanFactory后处理器
                this.invokeBeanFactoryPostProcessors(beanFactory);

                // 注册拦截bean创建的bean处理器
                //这里只是注册,真正调用是在getBean对时候
                this.registerBeanPostProcessors(beanFactory);

                //初始化消息资源
                this.initMessageSource();

                //初始化应用消息广播器
                this.initApplicationEventMulticaster();

                 // 模板方法,交给子类实现,允许子类来初始化其他Bean
                this.onRefresh();
                
                // 检查并注册监听器
                //在所有注册对bean中寻找Lestener bean,注册到消息广播器中
                this.registerListeners();

                // 5实例化非懒加载的单例
                this.finishBeanFactoryInitialization(beanFactory);
                //完成刷新过程
                //通知生命周期处理器刷新过程,发送广播事件
                //保证对应的监听器可以做进一步的逻辑处理
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

整个过程可以按代码中的注释下来,比较清晰。

  • 注释1,对系统属性或者环境变量的校验,设定一些标志。这步比较简单具体看validateRequiredProperties方法,它具体在AbstractPropertyResolver这个类中实现,主要是遍历属性,空的话记录异常。
  • 注释2,获取bean factory,即bean容器,并注册bean,具体看obtainFreshBeanFactory方法
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //BeanFactory在这步创建,并解析注册bean
        //具体在AbstractRefreshableApplicationContext类中实现该方法
        this.refreshBeanFactory();
        //获取BeanFactory
        return this.getBeanFactory();
    }

跟踪代码进入AbstractRefreshableApplicationContext类的refreshBeanFactory方法

	@Override
	protected final void refreshBeanFactory() throws BeansException {
		// 如果存在bean容器了,清理掉,并关闭已有的bean容器
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			//创建一个DefaultListableBeanFactory对象,它就是新的bean容器
			//这个类很重要
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			
			//对BeanFactory的扩展,添加了@Qualifier和@Autowired的支持
			customizeBeanFactory(beanFactory);
			
			// 这里就是注册bean了,跟之前分析BeanFactory的时候类似
			loadBeanDefinitions(beanFactory);
			
			// 由于 beanFactory 是公共变量,存在多线程操作,所以加锁操作,避免混乱修改
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

这一步非常重要,主要过程如下:
①先判断已有容器,如果存在,则清理掉,并关闭。
②创建一个DefaultListableBeanFactory对象,它就是新的bean容器
③设定序列号ID
④自定义BanFactory
⑤开始加载,即bean注册(核心方法)
⑥使用全局变量beanFactoryMonitor,记录BeanFactory实例

这里具体解析一下步骤⑤,loadBeanDefinitions方法在AbstractXmlApplicationContext类中实现

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 创建一个XmlBeanDefinitionReader 对象
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader);
    }

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = this.getConfigResources();
        if (configResources != null) {
            // 最终委托给XmlBeanDefinitionReader来执行loadBeanDefinitions
            reader.loadBeanDefinitions(configResources);
        }

        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
            // 最终委托给XmlBeanDefinitionReader来执行loadBeanDefinitions
            reader.loadBeanDefinitions(configLocations);
        }

    }

通过上面的源码我们可以看到AbstractRefreshableApplicationContext类中的loadBeanDefinitions方法为模板方法,交给子类AbstractXmlApplicationContext来实现,它通过创建XmlBeanDefinitionReader对象,来执行XmlBeanDefinitionReader对象的loadBeanDefinitions方法,这里就跟之前介绍的BeanFactory加载注册bean步骤一样。
最后可以通过getBeanFactory()来获取BeanFactory。
**※扩展说明:**这样AbstractApplicationContext就可以全部委托getBeanFactory方法来完成bean的管理配置,如下:

    //类似的方法都是通过委托getBeanFactory来实现的
    public Object getBean(String name) throws BeansException {
        this.assertBeanFactoryActive();
        return this.getBeanFactory().getBean(name);
    }

那这个getBeanFactory方法,在AbstractApplicationContext中只是个模板方法,具体由其子类AbstractRefreshableApplicationContext实现:

    //看,这里的beanFactory就是上面步骤6里面设置的BeanFactory实例
    public final ConfigurableListableBeanFactory getBeanFactory() {
        synchronized(this.beanFactoryMonitor) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext");
            } else {
                return this.beanFactory;
            }
        }
    }

好了,obtainFreshBeanFactory方法解析完了,现在知道AbstractApplicationContext为啥具备bean管理配置的能力了吧?
那继续看上面refresh中的注释3

  • 注释3,prepareBeanFactory方法,准备类加载器的环境,对前面获取到的 beanFactory进行各类扩展设置。包括 ClassLoader类加载器, post-processors后处理等的设置,增加对SPEL语言的支持、将相关环境变量及属性注册以单例模式注册等内容。

  • 注释4,invokeBeanFactoryPostProcessors
    实例化并调用所有注册的 BeanFactoryPostProcessor,这些是后处理器,处理类型是 BeanFactory, ApplicationContext容器允许在实例化 bean 前,读取 bean 信息和修改它的属性。就是说在实例化前,给用户最后一次机会去修改 bean 信息。(Spring里还有很多这类PostProcessor后置处理器,比如BeanPostProcessor等等,还是比较重要的,这里先不展开讲这些后处理器。)

  • 注释5,finishBeanFactoryInitialization
    完成 bean 容器的初始化,实例化所有剩余的(非非延迟加载)单例的bean

/**
	 * Finish the initialization of this context's bean factory,
	 * initializing all remaining singleton beans.
	 */
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		beanFactory.freezeConfiguration();

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

这里看到freezeConfiguration方法,是对bean定义的冻结,注册后的bean不可改了;preInstantiateSingletons方法就是实例化这些bean,这就是所谓的ApplicationContext容器初始化时,默认会将所有的单例bean提前进行初始化,就在这个方法。和BeanFactory不同,BeanFactory中的bean是在获取的时候才初始化。
查看PreInstantiateSingletons方法源码:

public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		//创建beanDefinitionNames的副本beanNames用于后续的遍历,以允许init等方法注册新的bean定义
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {

			//注释1. 获取beanName对应的MergedBeanDefinition
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

			// 判断bd这个Bean实例:不是抽象类 && 是单例 && 不是懒加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

				//注释2. 判断beanName对应的bean是否为FactoryBean
				if (isFactoryBean(beanName)) {

					//注释2-1. getBean('&'+beanName)将得到bean本身
					//通过getBean(beanName)拿到的是FactoryBean创建的Bean实例
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						//判断它是不是FactoryBean类型,然后获取FactoryBean实例
						final FactoryBean<?> factory = (FactoryBean<?>) bean;

						// 急切初始化标识
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}

						//注释2-2. 如果需急切初始化,则通过getBean(beanName)获取bean实例
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					//注释2-3 如果beanName对应的bean不是FactoryBean,只是普通Bean,通过getBean(beanName)获取bean实例
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		// 注释3. 遍历beanNames,触发post-initialization 回调
		for (String beanName : beanNames) {

			// 获取beanName对应的单例bean实例
			Object singletonInstance = getSingleton(beanName);

			//判断singletonInstance是否实现了SmartInitializingSingleton接口
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;

      				//触发SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

最后,refresh的最后一步是在finally代码块中的resetCommonCaches方法,用来清除缓存。

好了,以上就是ApplicationContext容器初始化的步骤。

通过BeanFactory容器和ApplicationContext容器的初始化步骤对比,可以知道两者的区别了吗?

总结

这里通过debug跟踪不同的容器初始化的步骤,这只是Spring的开始,通过对比知道两者的联系和区别。
BeanFactory是Spring IOC的基础,它是所有容器接口的父类。
ApplicationContext接口是BeanFactory的子类,对BeanFactory进行了扩展,使得ApplicationContext具有更多的功能;
ApplicationContext容器的初始化中包含了BeanFactory的初始化以及对BeanFactory的扩展,它通过getBeanFactory方法,把bean配置管理委托给BeanFactory;
ApplicationContext是初始化的时候就初始化所有的单例bean,BeanFactory中的bean是在获取的时候才初始化;
ApplicationContext增加了SPEL语言的支持(#{xx.xx}等配置)、 消息发送、响应机制(ApplicationEventPublisher)、支持了@Qualiiar和@Autowired等注解。
※细心的同学可能发现在上面的执行图中,BeanFactory里的bean定义数量有16个,而ApplicationContext立却有17个。原因就在于ApplicationContext容器对BeanFactory进行了扩展,它所注册的所有后处理器会遍历执行。MapperScannerConfigurer就是其中一个PostProcessor,而BeanFactory却没有这个功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值