ApplicationContext context = new ClassPathXmlApplicationContext("hello.xml");
    /**
*
* @param configLocations Spring的xml配置文件
* @param refresh 是否需要刷新,决定了是否进行bean解析、注册及实例化
* @param parent 父ApplicationContext
* @throws BeansException
*/
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
// 设置框架要加载的资源文件的位置<<AbstractRefreshableConfigApplicationContext>>
this.setConfigLocations(configLocations);
if (refresh) {
// ★
this.refresh(); // <AbstractApplicationContext>
}
}
	public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
// 容器预先准备,记录容器启动时间和标记
this.prepareRefresh();
// 创建bean工厂,里面实现了BeanDefinition的装载★
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 配置bean工厂的上下文信息,如类装载器等
this.prepareBeanFactory(beanFactory); try {
// 在BeanDefinition被装载后,提供一个修改BeanFactory的入口
postProcessBeanFactory(beanFactory);
this.postProcessBeanFactory(beanFactory);
// 在bean初始化之前,提供对BeanDefinition修改入口
// PropertyPlaceholderConfigurer在这里被调用
this.invokeBeanFactoryPostProcessors(beanFactory);
// 注册BeanPostProcessors,用于在bean被初始化时进行拦截,进行额外初始化操作
this.registerBeanPostProcessors(beanFactory);
// 初始化MessageSource
this.initMessageSource();
// 初始化上下文事件广播
this.initApplicationEventMulticaster();
// 这是一个模板方法
this.onRefresh();
// 注册监听器
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
...
} finally {
this.resetCommonCaches();
} }
} protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 如果存在BeanFactory则销毁并关闭
// 然后新建一个DefaultListableBeanFactory
// 然后进行BeanFactory的属性设置,设置是否允许重写BeanDefinition、是否允许循环引用
// 接着载入BeanDefinition<根据用途不同有多个实现子类>
this.refreshBeanFactory(); // <<AbstractRefreshableApplicationContext>>
return this.getBeanFactory();
}
// 例:具体实现子类AbstractXmlApplicationContext
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
this.initBeanDefinitionReader(beanDefinitionReader);
// ★
this.loadBeanDefinitions(beanDefinitionReader);
} // AbstractBeanDefinitionReader
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
// 取得ResourceLoader,这里是DefaultResourceLoader
ResourceLoader resourceLoader = this.getResourceLoader();
if (resourceLoader == null) {
...
} else {
int count;
// 路径模式解析,得到指向Bean定义信息的资源集合
if (resourceLoader instanceof ResourcePatternResolver) {
try {
// DefaultResourceLoader的getResources完成具体定位
Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
count = this.loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
} ... return count;
}...
} else {
// DefaultResourceLoader的getResources完成具体定位★
...
}
}
} ---开始获取资源--- // DefaultResourceLoader
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
Iterator var2 = this.protocolResolvers.iterator(); Resource resource;
do {
if (!var2.hasNext()) {
if (location.startsWith("/")) {
return this.getResourceByPath(location);
} if (location.startsWith("classpath:")) {
return new ClassPathResource(location.substring("classpath:".length()), this.getClassLoader());
} try {
URL url = new URL(location);
return (Resource)(ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
} catch (MalformedURLException var5) {
return this.getResourceByPath(location);
}
} ProtocolResolver protocolResolver = (ProtocolResolver)var2.next();
resource = protocolResolver.resolve(location, this);
} while(resource == null); return resource;
} ---资源获取完毕--- // XmlBeanDefinitionReader
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
// 将xml配置文件转成Document,这里使用了SAX对XML的解析
Document doc = this.doLoadDocument(inputSource, resource);
// ★
int count = this.registerBeanDefinitions(doc, resource);
}
...
} public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader(); // 通过反射获取
int countBefore = this.getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource)); // <<BeanDefinitionDocumentReader>>接口方法
return this.getRegistry().getBeanDefinitionCount() - countBefore;
} // 具体实现:DefaultBeanDefinitionDocumentReader
protected void doRegisterBeanDefinitions(Element root) {
// BeanDefinition的具体解析是由BeanDefinitionParserDelegate完成的
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
... this.preProcessXml(root);
// ★
this.parseBeanDefinitions(root, this.delegate);
this.postProcessXml(root);
this.delegate = parent;
} protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
// 对Document中元素、节点的不断解析。
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)) {
// 一个是默认标签的解析,如Spring自己定义的标签★
this.parseDefaultElement(ele, delegate);
} else {
// 一个是对自定义标签的解析,如自定义的标签
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
} } 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")) { // <DefaultListableBeanFactory> this.beanDefinitionMap.put(...);
this.processBeanDefinition(ele, delegate);
} else if (delegate.nodeNameEquals(ele, "beans")) {
// 递归
this.doRegisterBeanDefinitions(ele);
} } protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 这里是重点!!!BeanDefinition的具体解析是由BeanDefinitionParserDelegate完成的!!!★
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try {
// <<BeanDefinitionRegistry>> registerBeanDefinition(String var1, BeanDefinition var2) throws BeanDefinitionStoreException;
// 这里的BeanDefinition就是通过bdHolder获取的(definitionHolder.getBeanDefinition())
// 而DefaultListableBeanFactory实现了BeanDefinitionRegistry接口
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
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 取得<bean>中id、name、aliases等属性值
String id = ele.getAttribute("id");
String nameAttr = ele.getAttribute("name");
List<String> aliases = new ArrayList();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
aliases.addAll(Arrays.asList(nameArr));
}
... // 详细解析,比如构造函数、属性等
AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
...
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}...
} ---结束载入--- ---开始注册---
// DefaultListableBeanFactory
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
...
BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
...抛出异常 this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
if (this.hasBeanCreationStarted()) {
synchronized(this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
this.removeManualSingletonName(beanName);
}
} else {
// 正常注册流程
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName); this.removeManualSingletonName(beanName);
} this.frozenBeanDefinitionNames = null;
} if (existingDefinition != null || this.containsSingleton(beanName)) {
this.resetBeanDefinition(beanName);
} }

在Spring容器启动的过程中,会将类解析成Spring内部的BeanDefinition结构,并将BeanDefinition存储到DefaultListableBeanFactory中

DefaultListableBeanFactory是整Spring注册及加载Bean的默认实现

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
private volatile List<String> beanDefinitionNames = new ArrayList(256);

总结IoC容器的初始化过程:

  1. Resource定位(指的是BeanDefinition的资源定位,由ResourceLoader通过统一的Resource接口完成)
  2. BeanDefinition载入(把用户定义好的Bean表示成IoC容器内部的数据结构,即BeanDefinition)
  3. 向IoC容器注册BeanDefinition(BeanDefinitionRegistry)(在IoC容器内部将BeanDefinition注入到一个HashMap中,IoC容器通过HashMap持有BeanDefinition数据)

spring(四):IoC初始化流程&BeanDefinition加载注册的更多相关文章

  1. Spring IOC:BeanDefinition加载注册流程(转)

    BeanFactory接口体系 以DefaultListableBeanFactory为例梳理一下BeanFactory接口体系的细节 主要接口.抽象类的作用如下: BeanFactory(根据注册的 ...

  2. Spring中IoC - 两种ApplicationContext加载Bean的配置

    说明:Spring IoC其实就是在Service的实现中定义了一些以来的策略类,这些策略类不是通过 初始化.Setter.工厂方法来确定的.而是通过一个叫做上下文的(ApplicationConte ...

  3. Spring源码之IOC容器创建、BeanDefinition加载和注册和IOC容器依赖注入

    总结 在SpringApplication#createApplicationContext()执行时创建IOC容器,默认DefaultListableBeanFactory 在AbstractApp ...

  4. Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程

    上文,我们看了IOC设计要点和设计结构:紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的. ...

  5. SSH 之 Spring的源码(一)——Bean加载过程

    看看Spring的源码,看看巨人的底层实现,拓展思路,为了更好的理解原理,看看源码,深入浅出吧.本文基于Spring 4.0.8版本. 首先Web项目使用Spring是通过在web.xml里面配置 o ...

  6. Spring 系列教程之 bean 的加载

    Spring 系列教程之 bean 的加载 经过前面的分析,我们终于结束了对 XML 配置文件的解析,接下来将会面临更大的挑战,就是对 bean 加载的探索.bean 加载的功能实现远比 bean 的 ...

  7. linux文件系统初始化过程(5)---加载initrd(下)

    一.目的 linux把文件分为常规文件.目录文件.软链接文件.硬链接文件.特殊文件(设备文件.管道文件.socket文件等)几种类型,分别对应不同的新建函数sys_open().sys_mkdir() ...

  8. Html飞机大战(四):状态的切换(界面加载类的编辑)

    好家伙,接着写   既然我们涉及到状态了,那么我们也会涉及到状态的切换   那么我们怎样切换状态呢? 想象一下,如果我玩的游戏暂停了,那么我们肯定是通过点击或者按下某个按键来让游戏继续   这里我们选 ...

  9. Flex 界面初始化 自定义 预加载 类!

    说明: 自定义界面初始化过程提示:初始化...,初始化完毕,加载完毕! ZPreloader.as package com.command { import flash.display.Graphic ...

随机推荐

  1. 深入浅出Mybatis系列九-强大的动态SQL

    注:本文转载自南轲梦 注:博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 上篇文章<深入浅出Mybatis系列(八)---mapper映射文件配置之se ...

  2. codeforces 1284E

    计数每一个点被被其他点组成的四边形完全包含的四边形的个数,给出的点没有三点共线的情况 官方题解如下,说的很清楚,也很有技巧 代码也是直接参考官方的题解来的 #include<bits/stdc+ ...

  3. php 对象、json 、XML、数组互转

    对象转json $json=json_encode($postObj,JSON_FORCE_OBJECT); json转对象 $obj=json_encode($json); json转数组 $arr ...

  4. JDK线程池和Spring线程池的使用

    JDK线程池和Spring线程池实例,异步调用,可以直接使用 (1)JDK线程池的使用,此处采用单例的方式提供,见示例: public class ThreadPoolUtil { private s ...

  5. prach定点化处理

  6. c++中sort基础用法

    用法一:数组排序 对一个数组进行升序排序 #include <algorithm> #include <iostream> #include <cstdio> us ...

  7. LED Holiday Light-5 Mm Wide Angle Cone Lights: Pros

    But in rare cases, the opposite is true: the opinions of consultants are so synchronized that it is ...

  8. ALSA lib-io plugin

    https://www.alsa-project.org/alsa-doc/alsa-lib/pcm_external_plugins.html External Plugin: I/O Plugin ...

  9. [JSOI2013] 快乐的 JYY - 回文自动机,DFS

    #include <bits/stdc++.h> #define Sigma 30 #define MAXN 500010 #define int long long using name ...

  10. 微服务读取不到config配置中心配置信息,Spring Boot无法找到PropertySource:找不到标签Could not locate PropertySource: label not found

    服务出现报这个错, o.s.c.c.c.ConfigServicePropertySourceLocator - Could not locate PropertySource: label not ...