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. 刷题78. Subsets

    一.题目说明 题目78. Subsets,给一列整数,求所有可能的子集.题目难度是Medium! 二.我的解答 这个题目,前面做过一个类似的,相当于求闭包: 刷题22. Generate Parent ...

  2. cf1266D

    注意到每一个的点出入流是不会变的,因此本质是让构造一张图满足这个出入流并且边上的流量之和最少,显然流量是平衡的,也就是所有节点的出入流之和为0 因此我们可以直接暴力的选择让负数点向正数点连边,连之后就 ...

  3. liner-classifiers-SVM

    1支持向量机 参考看了这篇文章你还不懂SVM你就来打我 第一遍看完确实有想打死作者的冲动,但是多看几遍之后,真香~ [SVM---这可能是最直白的推导了] 个人觉得这篇文章讲的很清楚,条理清晰,数学推 ...

  4. 题解【洛谷P3456】[POI2007]GRZ-Ridges and Valleys

    题面 考虑 \(\text{Flood Fill}\). 每次在 \(\text{BFS}\) 扩展的过程中增加几个判断条件,记录山峰和山谷的个数即可. #include <bits/stdc+ ...

  5. BDA3 Chapter 1 Probability and inference

    1. uncertainty aleatoric uncertainty 偶然不确定性 epistemic uncertainty 认知不确定性 2. probability VS likelihoo ...

  6. PHPMailer发送邮件遇坑小记

    一:phpmailer发送邮件成功了 数据库发送状态也更改 但是用户就是没收到邮件. 出现原因:发送邮件太多 导致邮箱服务器被腾讯封了 发送的邮件统统进入了邮件服务器的草稿箱里. 解决方案: 重新修改 ...

  7. mysql 获取当前时间加上一个月

    select DATE_ADD(NOW(), interval 1 MONTH) NOW()此处必须为时间格式 date_add() 增加 date_sub()减少 month 月份 minute 分 ...

  8. Hibernate + mysql 配置

    1.生成po的配置 2.连接 MySQL 数据库的配合

  9. 小白月赛22 E : 方格涂色

    E:方格涂色 考察点 : 思维,模拟 坑点 : long long 其他的好像没什么,读懂题意就可以 AC 不要被样例画的图所迷惑 Code: #include <vector> #inc ...

  10. 杭电oj_2047——阿牛的EOF牛肉串(java实现)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2047 思路:先是列出了四个,但是没发现规律,然后开始画递归树,在其中找到了规律,算出递归式为f(n) ...