spring(四):IoC初始化流程&BeanDefinition加载注册
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容器的初始化过程:
- Resource定位(指的是BeanDefinition的资源定位,由ResourceLoader通过统一的Resource接口完成)
- BeanDefinition载入(把用户定义好的Bean表示成IoC容器内部的数据结构,即BeanDefinition)
- 向IoC容器注册BeanDefinition(BeanDefinitionRegistry)(在IoC容器内部将BeanDefinition注入到一个HashMap中,IoC容器通过HashMap持有BeanDefinition数据)
spring(四):IoC初始化流程&BeanDefinition加载注册的更多相关文章
- Spring IOC:BeanDefinition加载注册流程(转)
BeanFactory接口体系 以DefaultListableBeanFactory为例梳理一下BeanFactory接口体系的细节 主要接口.抽象类的作用如下: BeanFactory(根据注册的 ...
- Spring中IoC - 两种ApplicationContext加载Bean的配置
说明:Spring IoC其实就是在Service的实现中定义了一些以来的策略类,这些策略类不是通过 初始化.Setter.工厂方法来确定的.而是通过一个叫做上下文的(ApplicationConte ...
- Spring源码之IOC容器创建、BeanDefinition加载和注册和IOC容器依赖注入
总结 在SpringApplication#createApplicationContext()执行时创建IOC容器,默认DefaultListableBeanFactory 在AbstractApp ...
- Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程
上文,我们看了IOC设计要点和设计结构:紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的. ...
- SSH 之 Spring的源码(一)——Bean加载过程
看看Spring的源码,看看巨人的底层实现,拓展思路,为了更好的理解原理,看看源码,深入浅出吧.本文基于Spring 4.0.8版本. 首先Web项目使用Spring是通过在web.xml里面配置 o ...
- Spring 系列教程之 bean 的加载
Spring 系列教程之 bean 的加载 经过前面的分析,我们终于结束了对 XML 配置文件的解析,接下来将会面临更大的挑战,就是对 bean 加载的探索.bean 加载的功能实现远比 bean 的 ...
- linux文件系统初始化过程(5)---加载initrd(下)
一.目的 linux把文件分为常规文件.目录文件.软链接文件.硬链接文件.特殊文件(设备文件.管道文件.socket文件等)几种类型,分别对应不同的新建函数sys_open().sys_mkdir() ...
- Html飞机大战(四):状态的切换(界面加载类的编辑)
好家伙,接着写 既然我们涉及到状态了,那么我们也会涉及到状态的切换 那么我们怎样切换状态呢? 想象一下,如果我玩的游戏暂停了,那么我们肯定是通过点击或者按下某个按键来让游戏继续 这里我们选 ...
- Flex 界面初始化 自定义 预加载 类!
说明: 自定义界面初始化过程提示:初始化...,初始化完毕,加载完毕! ZPreloader.as package com.command { import flash.display.Graphic ...
随机推荐
- 剑指offer-面试题17-打印从1到最大的n位数-数字
/* 题目: 输入数字n,按顺序打印从1到最大的n位十进制数. 如输入3,打印从1,2,3到999. */ /* 思路: 大数问题转化为字符串或数组. */ #include<iostream& ...
- cookies欺骗-bugkuctf
解题思路: 打开链接是一串没有意义的字符串,查看源码没有发现什么,然后查看url,发现 filename的值是base64编码的,拿去解码 发现是一个文件,那么我们这里应该可以读取当前目录下的本地文件 ...
- 中间件c10k问题
中间件c10k问题 没有使用iocp/epoll/kqueue通讯的中间件,中间件就算部署在拥有多核CPU的强大服务器上,最头痛的问题是C10K问题. 中间件没有办法通过优化程序,提升CPU利用率来处 ...
- tmp = 2/4;竟然没有发现的
我还纠结着单目运算符和双目运算符和乘除的一些优先级什么事情. #include "common.h" #include <stdio.h> #include <s ...
- xampp安装配置比较容易卡住的地方
xampp作为一款集成建站软件,方便了不少初学的开发者,但是虽然是集成和傻瓜式的安装,还是会遇到一些容易卡壳的地方,这里记录自己觉得一些比较重要的东西. 1.端口问题 如图是我改之后的端口,原来端口为 ...
- H5_0019:JS中定义json结构
"7HKm": function(e, a, d) { "use strict"; Object ...
- 0005 uwsgi配置
在配置文件目录Configurations下创建一个名为uwsgi.ini的文件,用于uwsgi服务配置. uwsgi在服务器上使用,接收nginx的转发请求. 内容如下: # 配置文件:这一行必须有 ...
- 2020牛客寒假算法基础集训营1 I-nico和niconiconi
#include <bits/stdc++.h> #define dbg(x) cout << #x << "=" << x < ...
- 《深入理解java虚拟机》读书笔记九——第十章
第十章 早期(编译期)优化 1.Javac的源码与调试 编译期的分类: 前端编译期:把*.java文件转换为*.class文件的过程.例如sun的javac.eclipseJDT中的增量编译器. JI ...
- navicat 连接报2059错误
原因 navicat不支持mysql新版本的加密规则,mysql8 之前的版本中加密规则是mysql_native_password, mysql8之后,加密规则是caching_sha2_passw ...