@huangyichun
2017-07-25T09:29:50.000000Z
字数 16495
阅读 1015
Spring
注意该源码基于Spring 3.2版本分析的
public class MyTestBean {
private String testStr = "testStr";
public String getTestStr() {
return testStr;
}
public void setTestStr(String testStr) {
this.testStr = testStr;
}
}
<?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="myTestBean" class="chapter2.MyTestBean"/>
</beans>
public class BeanFactoryTest {
@Test
public void testSimpleLoad() {
ClassPathResource resource = new ClassPathResource("MyTestBean.xml");
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(resource);
MyTestBean bean = (MyTestBean) beanFactory.getBean("myTestBean");
Assert.assertEquals("testStr", bean.getTestStr());
}
}
总体时序图:
上面是Bean加载,解析,注册的时序图,下面先认识一些类的作用:
BeanDefinitionReader: 主要定义资源文件读取并转换为BeanDefinition的各个功能。
DocumentLoader: 定义从资源文件加载到转换为Document的功能
BeanDefinitionDocumentReader: 定义读取Document并注册BeanDefition功能
BeanDefinitionParseDelegate:定义解析Element的各种方法
BeanDefinitionReaderUtil:提供BeanDefinition的一些操作方法
BeanDefinitionRegistry: 定义对BeanDefinition的各种增删改查
DefaultListableBeanFactory: Spring Ioc容器的一种,同时也是实现了BeanDefinitionRegistry接口
//loadBeanDefinitions的具体实现,而EncodedResource主要用于对资源文件的处理
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());
}
//检查是否重复加载xml配置
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!");
}
// 调用DefaultResourceLoader的getResources方法完成具体的Resource定位
try {
//从EncodedResource中获取已经封装的Resource对象并再次从Resource中获取inputStream
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();
}
}
}
/**
* 真正的核心处理部分
* 如果不考虑冗余的代码,其实只做三件事:
* 1.获取XML文件的验证模式
* 2.加载XML,并获取Document.
* 3.返回的Document,注册Bean
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//获取XML验证模式,默认为XSD
int validationMode = getValidationModeForResource(resource);
// 取得XML文件的Document对象, 这个解析过程由DefaultDocumentLoader完成
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
// 启动对BeanDefinition解析的详细过程, 解析过程中会使用到Spring的Bean配置规则
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
//解析Xml文件,返回Document
return builder.parse(inputSource);
}
通过上面的过程已经完成了XML文件的加载,并且转换成document,接下来是提取和注册Bean。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//获取DefaultBeanDefinitionDocumentReader对Xml的BeanDefiniton进行解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//设置环境变量
documentReader.setEnvironment(this.getEnvironment());
//记录统计前BeanDefinition的加载个数
int countBefore = getRegistry().getBeanDefinitionCount();
//核心代码,加载及注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回本次加载的BeanDefinition个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//获取document的root
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);//核心代码
}
//--------------------------------------------------------
protected void doRegisterBeanDefinitions(Element root) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "environment property must not be null");
//处理root的profile属性,Spring存在两套配置方案,开发时和生产时,分别使用<beans profile="dev">...</beans>和<beans profile="product">..</beans>来进行配置
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
return;
}
}
//该类主要负责定义解析Element的各种方法
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createHelper(readerContext, root, parent);
// 解析Bean定义之前, 增强解析过程的可扩展性
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);//核心代码
// 解析Bean定义之后, 增强解析过程的可扩展性
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
// 获取Document对象根元素的所有子节点并循环解析
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)) {
// 解析Spring的Bean规则默认元素节点
parseDefaultElement(ele, delegate);
}
else {
//解析自定义节点元素
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 解析自定义元素根节点
delegate.parseCustomElement(root);
}
}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//解析import元素
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// 解析alias元素
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// 解析bean元素
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);//Bean处理的核心代码
}
// 解析内嵌beans元素, 作为根节点递归解析
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 递归解析
doRegisterBeanDefinitions(ele);
}
}
从代码可直接看出,Spring首先获取Document的根元素,然后取得根元素所有的子节点并循环解析这些子节点;如果子节点在Spring默认的命名空间内,则按照Spring Bean定义规则来解析,否则按照自定义的节点解析。在按照Spring Bean定义规则进行解析的parseDefaultElement方法中,完成了对< import/>、< alias/>、< bean/>、< beans/>等元素的解析。
BeanDefinitionParserDelegate类,主要定义了Spring默认的标签并且提供了Element的解析方法
这里只关注Spring对< bean >元素的解析过程
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 具体的解析委托给BeanDefinitionParserDelegate来完成
// BeanDefinitionHolder是BeanDefinition的封装类, 封装了BeanDefinition、Bean的名字和别名, 用它来完成向IoC容器注册.
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
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));
}
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
// 解析Bean定义资源文件中的<Bean>元素,主要处理<Bean>元素的id,name和aliase属性
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
// 如果<Bean>元素中没有配置id属性时, 将别名中的第一个值赋值给beanName
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 对<bean>元素进行详细解析
AbstractBeanDefinition beanDefinition = 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 = this.readerContext.generateBeanName(beanDefinition);
//为解析的Bean使用别名注册时, 为了向后兼容(Spring1.2/2.0给别名添加类名后缀)
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
//该方法解析Bean生成一个BeanDefinition
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 这里只读取<Bean>元素中配置的class名字, 然后载入到BeanDefinition中去
// 只是记录配置的class名字, 并不实例化, 对象的实例化在依赖注入时完成
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);
}
// 根据<Bean>元素配置的class名称和parent属性值创建BeanDefinition, 为载入Bean定义信息做准备
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 对当前<Bean>元素中配置的一些属性进行解析, 如singleton、abstract等
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 对<Bean>元素的meta(元数据)、lookup-method、replaced-method等子元素进行解析
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);// 解析<Bean>元素的构造方法参数
parsePropertyElements(ele, bd);// 解析<Bean>元素的<property>设置
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;
}
从上面分析可以看出,BeanDefinition就被载入到IoC容器后,就可以在容器中建立了数据映射了,剩下的就是BeanDefinition注册了。
该方法在上面已经分析过了,主要是将bean元素解析为BeanDefinition,并且将返回的BeanDefinition封装为BeanDefinitionHolder交给Ioc容器进行处理
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());//注册BeanDefinition
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 向IoC容器注册BeanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
}
}
}
这里的registry是DefaultListableBeanFactory,我们可以从下面的调用看出
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");
// 对解析得到的BeanDefinition校验
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 注册的过程中需要线程同步, 以保证数据的一致性
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.");
}
else {
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;
}
this.beanDefinitionMap.put(beanName, beanDefinition);//将beanDefinition放入map容器中
}
resetBeanDefinition(beanName);
}
//这个是Ioc容器中Bean的存储位置
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
以上是简单的Ioc容器bean解析,注册的所有过程。
总结下以上步骤:
使用ResourceLoader将配置文件读取为Resource,这里使用的是ClassPathLoader进行读取的。Resource代表着Spring的资源文件
调用DefaultDocumentLoader的loadDocument()方法,返回一个Document对象
调用DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法解析上面得到的document对象,具体的Element交给BeanDefinitionParserDelegate进行解析,得到BeanDefinitionHolder对象
使用BeanDefinitionReaderUtils的registerBeanDefinition注册上面的BeanDefinitionHolder对象,实际是将BeanDefinition注册到DefaultListableBeanFactory的ConcurrentHashMap对象中