spring源码-bean之初始化-1
一、spring的IOC控制反转:控制反转——Spring通过一种称作控制反转(IOC)的技术促进了松耦合。当应用了IOC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。说白了就是原本需要手动去创建和管理的对象,现在交给容器了。在容器的基础上,实现对象的控制。这个方式也很好的减少了开发者在框架上面的时间,更多关注点在业务逻辑上面。
二、这表博客的主要目的是研究,bean容器的初始化,会在最基本的bean初始化作源码的解析和分析。如何存在不妥当的地方,还请指出!
三、BeanFactory是spring的核心,通过工厂的模式来创建和使用bean。
四、我们都知道spring的bean初始化,依赖xml文件来实现的,所以这里重点讲解XmlBeanFactory的初始化过程。可能有人会问为什么不是ApplicationContext,相对于ApplicationContext,XmlBeanFactory是基础的bean初始化过程,后续我会单独将ApplicationContext又做了哪些动作。
五、源码解读
1)创建xml配置文件spring-bean.xml(这里省略User,,重点不在这里)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user" class="com.pinnet.customLabel.User"/>
</beans>
2)开始创建对象
package com.pinnet.bean; import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; public class Test { public static void main(String[] args) {
//读取资源
Resource resource = new ClassPathResource("spring-bean.xml");
//初始化容器
new XmlBeanFactory(resource);
}
}
3)初始化XmlBeanFactory
private final XmlBeanDefinitionReader reader; public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, (BeanFactory)null);
} public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//用XmlBeanDefinitionReader,来进行加载
this.reader = new XmlBeanDefinitionReader(this);
//解析资源
this.reader.loadBeanDefinitions(resource);
}
4)loadBeanDefinitions
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//包装成EncodedResource
return this.loadBeanDefinitions(new EncodedResource(resource));
} public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (this.logger.isInfoEnabled()) {
this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
} Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
} if (!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var6;
try {
//转换成InputStream流
InputStream inputStream = encodedResource.getResource().getInputStream(); try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//进一步解析
var6 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
inputStream.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if (((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var6;
}
}
5)doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
int validationMode = this.getValidationModeForResource(resource);
//读取xml为doc
Document doc = this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, validationMode, this.isNamespaceAware());
//注册BeanDefinition
return this.registerBeanDefinitions(doc, resource);
} catch (BeanDefinitionStoreException var5) {
throw var5;
} catch (SAXParseException var6) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var6.getLineNumber() + " in XML document from " + resource + " is invalid", var6);
} catch (SAXException var7) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var7);
} catch (ParserConfigurationException var8) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var8);
} catch (IOException var9) {
throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var9);
} catch (Throwable var10) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var10);
}
}
6)registerBeanDefinitions
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
this.logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
BeanDefinitionParserDelegate delegate = this.createHelper(readerContext, root);
//此方法用于提供子类处理之用
this.preProcessXml(root);
this.parseBeanDefinitions(root, delegate);
//此方法用于提供子类处理之用
this.postProcessXml(root);
}
7)parseBeanDefinitions(这一部分就是解析过程了)
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
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)) {
//默认标签解析
this.parseDefaultElement(ele, delegate);
} else {
//自定义标签解析(这里后面讲,这个也是非常重要的拓展功能)
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
} }
8)parseDefaultElement(默认标签解析,这里关注bean)
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")) {
this.processBeanDefinition(ele, delegate);
}
}
9)processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//这里主要是解析过程
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//这里注册bean到beanDefinitionMap,后面会看到
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));
}
}
a、parseBeanDefinitionElement
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
} public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
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((Collection)Arrays.asList(nameArr));
} String beanName = id;
if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
beanName = (String)aliases.remove(0);
if (this.logger.isDebugEnabled()) {
this.logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
}
} if (containingBean == null) {
//检查id和别名是否重复
this.checkNameUniqueness(beanName, aliases, ele);
} //解析过程
AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
} else {
//生成beanName
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
}
} catch (Exception var9) {
this.error(var9.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
//将别名和beanName放入BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
} else {
return null;
}
}
parseBeanDefinitionElement(进一步解析过程,可以自己查看源码,这里不讲解)
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute("class")) {
className = ele.getAttribute("class").trim();
}
try {
String parent = null;
if (ele.hasAttribute("parent")) {
parent = ele.getAttribute("parent");
}
//创建GenericBeanDefinition
AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
//解析bean上面的默认元素
this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
//meta
this.parseMetaElements(ele, bd);
//lookup-method
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//replaced-method
this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//constructor-arg
this.parseConstructorArgElements(ele, bd);
//property
this.parsePropertyElements(ele, bd);
//qualifier
this.parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(this.extractSource(ele));
//所有解析过后的元素全部放在AbstractBeanDefinition里面
AbstractBeanDefinition var8 = bd;
return var8;
} 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;
}
b、registerBeanDefinition(将AbstractBeanDefinition的相关数据放入beanDefinitionMap)
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var7 = aliases;
int var6 = aliases.length; for(int var5 = 0; var5 < var6; ++var5) {
String aliase = var7[var5];
registry.registerAlias(beanName, aliase);
}
} }
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition)beanDefinition).validate();
} catch (BeanDefinitionValidationException var6) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var6);
}
} Map var3 = this.beanDefinitionMap;
synchronized(this.beanDefinitionMap) {
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
} if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
} else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
//将beanName和beanDefinition形成键值对的形式,保存在Map中
this.beanDefinitionMap.put(beanName, beanDefinition);
this.resetBeanDefinition(beanName);
}
}
六、好了,这就是源码的实现过程,中间省略了很多的判定和实现过程。主要的流程,基本上就是这样。这里重点注意几个点,也是对流程的梳理
1)初始化XmlBeanFactory,需要注意XmlBeanDefinitionReader:这是整个解读过程的关键
2)然后就是字符集包装,然后形成流EncodedResource、inputSource
3)解析xml,基本上是通过spring的DefaultDocumentLoader实现的,通过对Document文档的解析来实现标签和元素的解析
4)判断是否是默认标签是通过xml的Namespace来实现的,默认Namespace的读取目录是通过DefaultNamespaceHandlerResolver来实现的,也就是读取spring.handlers和spring.schemas,后续会讲到这两个文件的作用
public boolean isDefaultNamespace(String namespaceUri) {
return !StringUtils.hasLength(namespaceUri) || "http://www.springframework.org/schema/beans".equals(namespaceUri);
}
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
return new DefaultNamespaceHandlerResolver(this.getResourceLoader().getClassLoader());
}
spring.handlers
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
spring.schemas
http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
5)解析bean标签,是生产一个GenericBeanDefinition这个类是继承AbstractBeanDefinition生产BeanDefinition的过程其实就是讲标签里面的元素进行解析放入的过程
6)注册的过程是放在DefaultListableBeanFactory里面的beanDefinitionMap,是不是有点奇怪过程并没有DefaultListableBeanFactory。在源码的9)中使用了BeanDefinitionRegistry ,而这个BeanDefinitionRegistry 也是我们最开始使用的XmlBeanFactory,但是XmlBeanFactory,并没有太多的实现。看来一个结构:
其实最开始调用XmlBeanFactory的时候就已经使用了DefaultListableBeanFactory,值不够是继承关系而已。所以这里基本上所有的数据都在DefaultListableBeanFactory里面了
7)最后解析过程就到这里,主要数据全部在DefaultListableBeanFactory的beanDefinitionMap里面。
8)注意一点,别名的加载过程也很重要,这里不多介绍,多想法自己查看源码
七、容器的初始化基本上就是这样了,主要是梳理流程和spring在IOC的控制中做了什么。
spring源码-bean之初始化-1的更多相关文章
- spring源码-bean之增强初始化-3
一.ApplicationContext的中文意思是“应用上下文”,它继承自BeanFactory接口,除了包含BeanFactory的所有功能之外,在国际化支持.资源访问(如URL和文件).事件传播 ...
- spring源码-bean之加载-2
一.前面说了bean的容器初始化,后面当然是说bean的加载.这里还是不讲解ApplicationContext的bean的加载过程,还是通过最基础的XmlBeanFactory来进行讲解,主要是熟悉 ...
- Spring源码--Bean的管理总结(一)
前奏 最近看了一系列解析spring管理Bean的源码的文章,在这里总结下,方便日后复盘.文章地址https://www.cnblogs.com/CodeBear/p/10336704.html sp ...
- spring源码分析之初始化过程
1.org.springframework.web.context.ContextLoaderListener 一个ServletContextListener,web容器启动监听器 1.1内有成员C ...
- Spring源码-Bean生命周期总览
- spring源码-自定义标签-4
一.自定义标签,自定义标签在使用上面相对来说非常常见了,这个也算是spring对于容器的拓展.通过自定义标签的方式可以创造出很多新的配置方式,并且交给容器直接管理,不需要人工太多的关注.这也是spri ...
- spring源码-开篇
一.写博客也有一段时间了,感觉东西越来越多了,但是自己掌握的东西越来越少了,很多时候自己也在想.学那么多东西,到头来知道的东西越来越少了.是不是很奇怪,其实一点都不奇怪. 我最近发现了一个很大的问题, ...
- spring源码-BeanPostProcessor-3.3
一.BeanPostProcessor这个是spring容器的拓展之一,是用于获取bean的时候处理对应的对象: 二.常用场景,在获取bean的时候,重新初始化bean的属性等. 三.实现方式(加入容 ...
- Spring源码剖析依赖注入实现
Spring源码剖析——依赖注入实现原理 2016年08月06日 09:35:00 阅读数:31760 标签: spring源码bean依赖注入 更多 个人分类: Java 版权声明:本文为博主原 ...
随机推荐
- js获取7天之前或之后的日期
function fun_date(aa){ var date1 = new Date(), time1=date1.getFullYear()+"-"+(date1.getMon ...
- 体验了Sublime + Emmet,才体会到原来前端开发可以这么痛快!
从当初用notepad写出第一个web页面,到现在偶尔使用Editplus做一些HTML5的消遣,不知不觉已经15年了 --! 在这中间,和那些老顽固一样,坚决远离FP.DW那些半自动的前端开发工具 ...
- Gluon Data API
http://mxnet.apache.org/api/python/gluon/data.html import sys import os import time import mxnet as ...
- js 构造函数创建钟表
翻出来之前的一些效果,觉得这个时钟还挺好玩的就写出来共大家分享: HTML代码如下: <div id="box"> </div> 当前盒子用于插入钟表内容: ...
- n维向量旋转(循环移位)——学习《编程珠玑》
问题: 将一个n元一维向量向左旋转i个位置.例如,当n=8且i=3时,向量abcdefgh旋转为defghabc. 简单的代码使用一个n元的中间向量在n步内完成该工作. 你能否仅使用数十个额外字节的存 ...
- Java中int和String的转换问题
int -> String int i=12345;String s="";第一种方法:s=i+"";第二种方法:s=String.valueOf(i); ...
- CRegKey 注册表操作 转
转自 http://blog.csdn.net/pbymw8iwm/article/details/6931946 1.简介 CRegKey提供了对系统注册表的操作方法,通过CRegKey类,可以方便 ...
- LwIP协议栈开发嵌入式网络的三种方法分析
LwIP协议栈开发嵌入式网络的三种方法分析 摘要 轻量级的TCP/IP协议栈LwIP,提供了三种应用程序设计方法,且很容易被移植到多任务的操作系统中.本文结合μC/OS-II这一实时操作系统,以 ...
- LeetCode20.有效的括号 JavaScript
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭合. 注意空字符串可被认 ...
- 大数据框架-YARN
YARN(Yet Another Resource Negotiator): 是一种新的 Hadoop 资源管理器 [ResourceManager:纯粹的调度器,基于应用程序对资源的需求进行调度的, ...