Spring源码解读 IOC容器初始化
2017-03-07 21:41
597 查看
前言
自己对IOC容器和Spring容器理解是不一样,在我看来IOC容器的基本功能就是获取Bean,没有其它功能。而spring容器就是在IOC容器基础上扩展了许多功能,例如生命周期
的管理,支持不同的信息源,应用事件等等。而本篇文章主要就是来分析IOC容器的初始化过程,通过分析这一过程让我们了解,我们定义好bean之后,spring内部做了些什
么。分析源码的版本是spring4.1.7。
正文
在分析之前先看一下配置文件和代码,都是最简单的。凡是都是由浅入深吗。
配置文件
实体类
测试代码
整个配置和代码都非常简单,自己觉得对于了解其原理的话,足够了。
从上面的代码中可以猜到IOC容器的初始化过程,在ClassPathXMLApplicationContext的构造方法中。调试代码,发现确实如此。
先看一下ClassPathXmlApplication的构造方法,
setConfigLocations()方法主要是讲我们传入的参数"spring.xml"设置进入,没什么可说的。看来主要逻辑在refresh()方法中。refresh()方法如下:
整个方法有很多功能,分别针对spring容器各个功能进行初始化,而本篇文章要分析的IOC容器的初始化在方法过程2,obtainFreshBeanFactory()方法中,在该方法中有调
用了refreshBeanFactory(),从名字也可以看出来初始化IOC容器的过程在这个方法里。
在看loadBeanDefitions()方法
又是一个loadBeanDefitions()方法,不过这次参数的类型是XmlBeanDefinitionReader。在看这个方法
还是loadBeanDefitions()方法,不过这里是调用XmlBeanDefitionReader的。我调试的时候走的是下面的那个逻辑,在看下面的那个loadBeanDefitions()方法。中间
还有很多简单的loadBeanDefitions()方法,在此不表,在看下面俩个主要的loadBeanDefitions()方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//获取resource的流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
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();
}
}
}
漫无止境的loadBeanDefitions方法终于结束了,突然想到了动漫凉宫春日的忧郁里漫无止境的八月的剧情,如果动漫里那么多次八月的循环只是春日为了换回阿虚的一次挽
留,那么这么多漫无止境loadBeanDefitions()的调用就是为了获取我们定义bean文件的流。好像用如果...那么不合适,不过不要紧反正都是自以为。
说了一些有的没的,回到正题,loadBeanDefitions()里出现了Resource,ResourceLoader,ResourcePatternResoulver。
Resource就是spring对我们定义bean文件的抽象,里面声明了获取InputStream的方法。
ResourceLoader定义了如何通过路径抽象成Resource
ResourcePatternResoulver 实现了ResourceLoader,可以传入一个多个路径。
总结一下IOC容器初始化的第一步就是通过ResourceLoader根据文件路径转换成Resource,然后通过Resource获取这个文件的流。
在看一下doLoadBeanDefitions()方法,主要代码如下:
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
将IO流,解析成document文档,然后再看一下registerBeanDefitions()方法,
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
声明一个BeanDefitionDocumentReader来解析document文档,再看一下doucmetReader的registerBeanDefitions()方法,
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
获取文档的根元素,然后通过解析根元素,再看一下doRegisterBeanDefitions()方法,
protected void doRegisterBeanDefinitions(Element root) {
//BeanDefinitionParserDelegate里包含了spring bean定义规则的处理,
//用它来讲document文档,解析成spring内部使用的数据结构BeanDefition
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
preProcessXml(root);
//将document文档解析成BeanDeftions的过程。
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
再看一下parseBeanDefitons()方法
if (delegate.isDefaultNamespace(root)) {
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)) {
//解析默认的元素
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
再看一下parseDefaultELement()方法,
//处理导入的文件
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//解析别名
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//解析Bean
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//解析Beans
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
看一下如何解析Bean
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//将元素解析成BeanDefinitonHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//将BeanDefitinionHolder注入容器
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
在这里说明一下BeanDefinitionHolder是BeanDefinition的封装,封装了BeanDefition,bean的名字和别名。而BeanDefition就是spring就是我们定义的各种bean在spring内部的数据结构。
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
//获取Bean中设置的class的名字,载入到BeanDefitions中
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//生创建BeanDefition对象,为Bean定义信息的载入做准备
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//对当前Bean元素进行属性解析,并设置到descrition
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析Bean的各种元素
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析bean的构造函数
parseConstructorArgElements(ele, bd);
//解析bean的属性
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
在这里个人对spring IOC容器的初始化的研究就结束了,至于具体怎么解析bean的各种元素,个人认为不重要,无非就是各种解析XML的规则而已。而整个spring IOC容器加载的过程与结果我认为自己已经了解了。最后做一下总结。
IOC容器初始化主要过程
1.通过ResourceLoader将文件路径转换成Resource。
2.通过Resource获取InputStream
3.通过BeanDefinitionDocumentReader将IO流转换成Document
4.通过BeanDefinitionParserDelegate 把文档中的元素解析成BeanDefinition并放到BeanDefinitionHolder中。
5.将BeanDefinition注册到BeanFactory中。
自己对IOC容器和Spring容器理解是不一样,在我看来IOC容器的基本功能就是获取Bean,没有其它功能。而spring容器就是在IOC容器基础上扩展了许多功能,例如生命周期
的管理,支持不同的信息源,应用事件等等。而本篇文章主要就是来分析IOC容器的初始化过程,通过分析这一过程让我们了解,我们定义好bean之后,spring内部做了些什
么。分析源码的版本是spring4.1.7。
正文
在分析之前先看一下配置文件和代码,都是最简单的。凡是都是由浅入深吗。
配置文件
<bean id="user" class="vo.User"> <property name="name" value="czy" /> </bean>
实体类
package vo; public class User { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } }
测试代码
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml"); User u = (User) ctx.getBean("user"); System.out.println(u.getName());
整个配置和代码都非常简单,自己觉得对于了解其原理的话,足够了。
从上面的代码中可以猜到IOC容器的初始化过程,在ClassPathXMLApplicationContext的构造方法中。调试代码,发现确实如此。
先看一下ClassPathXmlApplication的构造方法,
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
setConfigLocations()方法主要是讲我们传入的参数"spring.xml"设置进入,没什么可说的。看来主要逻辑在refresh()方法中。refresh()方法如下:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //1. 刷新前的准备工作 prepareRefresh(); //2. 关闭释放旧的beanFactory创建新的beanFactory,读取配置文件等 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //3. 对beanFactory进行一些基本的初始化 prepareBeanFactory(beanFactory); try { //4. 下面两行主要用户扩展,处理所有已注册的BeanFactoryPostProcessor,实现在已经加载配置但未初始化bean时对配置进行修改 postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); //5. 处理所有已注册的BeanPostProcessor,主要用于扩展,实现bean初始化前后的一些定制操作 registerBeanPostProcessors(beanFactory); //6. 初始化消息源bean initMessageSource(); //7. 初始化事件监听器集,也有人叫事件监听器的注册表,所有的事件监听器都在这个bean里进行管理 initApplicationEventMulticaster(); //8. 主要用于扩展,实现一些特殊bean的初始化,时间点是类似消息源事件监听器集等特殊bean初始化后,普通的bean初始化前 onRefresh(); //9. 注册监听器 registerListeners(); //10. 初始化其余的非延迟加载的单例bean finishBeanFactoryInitialization(beanFactory); //11. 刷新完成调用LifecycleProcessor的onRefresh方法,并且发布ContextRefreshedEvent事件 finishRefresh(); } catch (BeansException ex) { // 销毁已经创建的单例bean destroyBeans(); // 重新设置active标记 cancelRefresh(ex); throw ex; } } }
整个方法有很多功能,分别针对spring容器各个功能进行初始化,而本篇文章要分析的IOC容器的初始化在方法过程2,obtainFreshBeanFactory()方法中,在该方法中有调
用了refreshBeanFactory(),从名字也可以看出来初始化IOC容器的过程在这个方法里。
protected final void refreshBeanFactory() throws BeansException { //1.如果已经有了beanFactory则销毁所有的bean,并关闭beanFactory if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //2.创建BeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); //3.设置BeanFactory的Id,ID是个弱引用。 beanFactory.setSerializationId(getId()); //4.应用上下文使用的自定义BeanFactory customizeBeanFactory(beanFactory); //5.解析我们定义的bean,并添加到beanFactory loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
在看loadBeanDefitions()方法
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 为指定的BeanFactory创建了一个新的XmlBeanDefinitionReader XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // 设置beanDefinitionReader的参数 beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //初始化BeanDefitionReader initBeanDefinitionReader(beanDefinitionReader); //通过beanDefitionReader解析我们定义的bean loadBeanDefinitions(beanDefinitionReader); }
又是一个loadBeanDefitions()方法,不过这次参数的类型是XmlBeanDefinitionReader。在看这个方法
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //获取资源,然后再次调用XmlBeanDefinitionReader的loadBeanDefinitions()方法 Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
还是loadBeanDefitions()方法,不过这里是调用XmlBeanDefitionReader的。我调试的时候走的是下面的那个逻辑,在看下面的那个loadBeanDefitions()方法。中间
还有很多简单的loadBeanDefitions()方法,在此不表,在看下面俩个主要的loadBeanDefitions()方法
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // 将我们定义的文件通过ResourceLoader转换成Resource try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//获取resource的流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
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();
}
}
}
漫无止境的loadBeanDefitions方法终于结束了,突然想到了动漫凉宫春日的忧郁里漫无止境的八月的剧情,如果动漫里那么多次八月的循环只是春日为了换回阿虚的一次挽
留,那么这么多漫无止境loadBeanDefitions()的调用就是为了获取我们定义bean文件的流。好像用如果...那么不合适,不过不要紧反正都是自以为。
说了一些有的没的,回到正题,loadBeanDefitions()里出现了Resource,ResourceLoader,ResourcePatternResoulver。
Resource就是spring对我们定义bean文件的抽象,里面声明了获取InputStream的方法。
ResourceLoader定义了如何通过路径抽象成Resource
ResourcePatternResoulver 实现了ResourceLoader,可以传入一个多个路径。
总结一下IOC容器初始化的第一步就是通过ResourceLoader根据文件路径转换成Resource,然后通过Resource获取这个文件的流。
在看一下doLoadBeanDefitions()方法,主要代码如下:
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
将IO流,解析成document文档,然后再看一下registerBeanDefitions()方法,
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
声明一个BeanDefitionDocumentReader来解析document文档,再看一下doucmetReader的registerBeanDefitions()方法,
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
获取文档的根元素,然后通过解析根元素,再看一下doRegisterBeanDefitions()方法,
protected void doRegisterBeanDefinitions(Element root) {
//BeanDefinitionParserDelegate里包含了spring bean定义规则的处理,
//用它来讲document文档,解析成spring内部使用的数据结构BeanDefition
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
preProcessXml(root);
//将document文档解析成BeanDeftions的过程。
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
再看一下parseBeanDefitons()方法
if (delegate.isDefaultNamespace(root)) {
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)) {
//解析默认的元素
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
再看一下parseDefaultELement()方法,
//处理导入的文件
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//解析别名
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//解析Bean
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//解析Beans
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
看一下如何解析Bean
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//将元素解析成BeanDefinitonHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//将BeanDefitinionHolder注入容器
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
在这里说明一下BeanDefinitionHolder是BeanDefinition的封装,封装了BeanDefition,bean的名字和别名。而BeanDefition就是spring就是我们定义的各种bean在spring内部的数据结构。
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
//获取Bean中设置的class的名字,载入到BeanDefitions中
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//生创建BeanDefition对象,为Bean定义信息的载入做准备
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//对当前Bean元素进行属性解析,并设置到descrition
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析Bean的各种元素
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析bean的构造函数
parseConstructorArgElements(ele, bd);
//解析bean的属性
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
在这里个人对spring IOC容器的初始化的研究就结束了,至于具体怎么解析bean的各种元素,个人认为不重要,无非就是各种解析XML的规则而已。而整个spring IOC容器加载的过程与结果我认为自己已经了解了。最后做一下总结。
IOC容器初始化主要过程
1.通过ResourceLoader将文件路径转换成Resource。
2.通过Resource获取InputStream
3.通过BeanDefinitionDocumentReader将IO流转换成Document
4.通过BeanDefinitionParserDelegate 把文档中的元素解析成BeanDefinition并放到BeanDefinitionHolder中。
5.将BeanDefinition注册到BeanFactory中。
相关文章推荐
- Spring源码解读-Spring IoC容器初始化之资源解析
- Spring:源码解读(IOC容器的初始化)
- Spring源码解读-Spring IoC容器初始化之资源定位
- Spring源码解读-Spring IoC容器初始化之资源注册
- spring源码研究之IoC容器在web容器中初始化过程
- Spring源码分析(二)-Spring IoC容器的初始化No.2
- Spring源码分析(二)-Spring IoC容器的初始化No.1
- spring源码学习之路---深度分析IOC容器初始化过程(四)
- Spring IOC容器bean初始化源码分析
- Spring源码阅读之IoC容器初始化1 -- Resource定位
- Spring源码解读5——IoC容器的高级特性
- 【Spring】IOC核心源码学习(二):容器初始化过程
- Spring源码解读——Spring容器初始化 2
- spring beans源码解读之 ioc容器之始祖--DefaultListableBeanFactory
- 初始化IoC容器(Spring源码阅读)-我们到底能走多远系列(31)
- 深入学习Spring源码---基本IOC容器初始化
- Spring源码阅读(一):IOC容器的初始化
- spring beans源码解读之 ioc容器之始祖--DefaultListableBeanFactory
- spring源码学习之路---IOC容器初始化要义之bean定义载入(五)
- spring源码学习之路---IOC容器初始化要义之bean定义载入(五)