Spring源码学习-3.IoC.资源的加载与注册
2015-08-01 19:12
591 查看
ApplicationContext中资源加载是IOC容器初始化的第二步,
第一步定位资源已经在上一篇中完成了,这一篇我们就来分析一下,IoC资源是怎么加载到BeanDefinition中的.
refresh()方法出现在FileSystemXmlApplicationContext的构造函数中
refresh()是BeanDefinition加载的入口,下面我们来看refresh方法源码
获取工程实例的代码
AbstractApplicationContext的子类 AbstractRefreshableApplicationContext实现了refreshBeanFactory这个抽象方法
关于BeanDefinition的加载全都在子类对于这个方法的实现中
AbstractXmlApplicationContext中实现了 上面代码中的loadBeanDefinitions(beanFactory)抽象方法
解析XML,获取Document对象的代码:
详细探究XML解析过程:
parse和getDocument都是DOMParser下面的两个函数:
具体解析过程没怎么看明白~~
调用了com.sun.org.apache.xerces.internal.parsers.XML11Configuration里面的方法和
XMLVersionDetector里面的startDocumentParsing方法
得到Document以后就是将BeanDefinition信息载入到Map中
接下来调用DefaultBeanDefinitionDocumentReader 类封装BeanDefinition
接下来就是开始分析XML文件中标签属性了
三种不同情况,分别解析,(产生一个疑问,那Spring配置文件中其他的标签如何加载???)
对于import 这个引入其他配置文件的标签的处理思路是:
先验证这个链接是否正确,然后定位这个资源,如果这个资源合法最后载入这一个资源,并发送处理完成事件
最重要的就是对于Bean的解析了调用这个方法开始解析: BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
加载类名,ID等主要的属性
下面进入BeanDefinitionParserDelegate类中的方法
加载完主要信息,开始加载其他Element标签的信息
BeanDefinitionReaderUtils 里面加载了classLoader parent等属性
下面就是解析构造函数的具体实现了
解析Property的实现
对每个property节点分别解析
取得property元素的值,也许是个list或者其他的
通过对上述源码的分析,我们可以了解在Spring配置文件中,<Bean>元素中<property>元素的相关配置是如何处理的:
a. ref被封装为指向依赖对象一个引用。
b.value配置都会封装成一个字符串类型的对象。
c.ref和value都通过“解析的数据类型属性值.setSource(extractSource(ele));”方法将属性值/引用与所引用的属性关联起来。
在方法的最后对于<property>元素的子元素通过parsePropertySubElement 方法解析,我们继续分析该方法的源码,了解其解析过程。
6.解析<property>元素的子元素:
在BeanDefinitionParserDelegate类中的parsePropertySubElement方法对<property>中的子元素解析,源码如下:
解析List
经过对Spring Bean定义资源文件转换的Document对象中的元素层层解析,Spring IoC现在已经将XML形式定义的Bean定义资源文件转换为Spring IoC所识别的数据结构——BeanDefinition,它是Bean定义资源文件中配置的POJO对象在Spring IoC容器中的映射,我们可以通过AbstractBeanDefinition为入口,荣IoC容器进行索引、查询和操作。
通过Spring IoC容器对Bean定义资源的解析后,IoC容器大致完成了管理Bean对象的准备工作,即初始化过程,但是最为重要的依赖注入还没有发生,现在在IoC容器中BeanDefinition存储的只是一些静态信息,接下来需要向容器注册Bean定义信息才能全部完成IoC容器的初始化过程。
注册的过程就是将处理好的BeanDefinition加入到 BeanDefinitionMap中
处理注册的代码在DefaultListableBeanFactory中
第一步定位资源已经在上一篇中完成了,这一篇我们就来分析一下,IoC资源是怎么加载到BeanDefinition中的.
refresh()方法出现在FileSystemXmlApplicationContext的构造函数中
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
refresh()是BeanDefinition加载的入口,下面我们来看refresh方法源码
//这个方法描述了整个ApplicationContext的初始化方法 public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //准备刷新的方法,获取时间,设置同步标志 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //调用子类的resfreshFactory()。获得工厂实例 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //初始化:配置容器属性,如ClassLoader,事件处理器 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //设置后置处理 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //加载所有参与的Bean invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. //初始化信息源,与国际化有关 initMessageSource(); // Initialize event multicaster for this context. //初始化容器事件传播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. //子类某些特殊Bean初始化方法 //子类重写onRefresh后,到底会调用哪个OnRefresh()? onRefresh(); // Check for listener beans and register them. //为传播器注册监听器 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.容器生命周期事件 finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. beanFactory.destroySingletons(); // Reset 'active' flag.重置同步标识 cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
获取工程实例的代码
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //父类定义了抽象的refreshBeanFactory()方法,具/体实现调用子类容器的refreshBeanFactory()方法 refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
AbstractApplicationContext的子类 AbstractRefreshableApplicationContext实现了refreshBeanFactory这个抽象方法
关于BeanDefinition的加载全都在子类对于这个方法的实现中
protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); //抽象方法 AbstractXmlApplicationContext实现, //委派模式 // 然后调用AbstractXmlApplicationContext //的loadBeanDefinitions(XmlBeanDefinitionReader) synchronized (this.beanFactoryMonitor) { //beanFactoryMonitor 监视器 this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException( "I/O error parsing XML document for application context [" + getDisplayName() + "]", ex); } }
AbstractXmlApplicationContext中实现了 上面代码中的loadBeanDefinitions(beanFactory)抽象方法
<pre name="code" class="java"> protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); // BeanDefinition加载开始 loadBeanDefinitions(beanDefinitionReader); } //也是这个AbstractXmlApplicationContext类中的方法 // 通过BeanFactory生成了 XmlBeanDefinitionReader 通过Resource和String两种方式加载BeanDefinitions protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
</pre><p>后面的代码中调用了若干个参数不同的loadBeanDefinition方法</p><p></p><p>loadBeanDefinitions的参数变化<span style="white-space: pre;"> </span></p>loadBeanDefinitions(DefaultListableBeanFactory beanFactory) loadBeanDefinitions(String[] locations)loadBeanDefinitions(String location)loadBeanDefinitions(String location, Set actualResources)loadBeanDefinitions(Resource[] resources)loadBeanDefinitions(Resource resource) loadBeanDefinitions(EncodedResource encodedResource)<p>最后调用了 int doLoadBeanDefinitions(InputSource inputSource, Resource resource)这里实现了加载loadBeanDefinitions的代码</p><p><pre name="code" class="java">protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource); Document doc = this.documentLoader.loadDocument(//解析XML文件,获取Document对象 inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); // 容器按照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); } }
解析XML,获取Document对象的代码:
// 加载Domcument的地方 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); return builder.parse(inputSource); }
详细探究XML解析过程:
// DocumentBuilderImpl 中的parse方法 public Document parse(InputSource is) throws SAXException, IOException { if (is == null) { throw new IllegalArgumentException( DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "jaxp-null-input-source", null)); } if (fSchemaValidator != null) { if (fSchemaValidationManager != null) { fSchemaValidationManager.reset(); } resetSchemaValidator(); } domParser.parse(is);//开始解析 return domParser.getDocument();//得到Document对象 }
parse和getDocument都是DOMParser下面的两个函数:
具体解析过程没怎么看明白~~
调用了com.sun.org.apache.xerces.internal.parsers.XML11Configuration里面的方法和
XMLVersionDetector里面的startDocumentParsing方法
得到Document以后就是将BeanDefinition信息载入到Map中
//XmlBeanDefinitionReader 中的 注册方法 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // Support old XmlBeanDefinitionParser SPI for backwards-compatibility. // 不使用这个 if (this.parserClass != null) { XmlBeanDefinitionParser parser = (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass); return parser.registerBeanDefinitions(this, doc, resource); } // Read document based on new BeanDefinitionDocumentReader SPI. // BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); // 具体解析过程在这里实现 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
接下来调用DefaultBeanDefinitionDocumentReader 类封装BeanDefinition
// DefaultBeanDefinitionDocumentReader 类 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); // //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性 preProcessXml(root); // 这一步为解析过程 parseBeanDefinitions(root, delegate); // //在解析Bean定义之后,进行自定义的解析,增强解析过程的可扩展性 postProcessXml(root); } // 也在DefaultBeanDefinitionDocumentReader这个类中parseBeanDefinitions方法 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //Bean定义的Document对象使用了Spring默认的XML命名空间 if (delegate.isDefaultNamespace(root.getNamespaceURI())) { 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; String namespaceUri = ele.getNamespaceURI(); if (delegate.isDefaultNamespace(namespaceUri)) { // 如果使用了默认的,就在此解析 parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
接下来就是开始分析XML文件中标签属性了
//默认解析过程 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //如果元素节点是<Import>导入元素,进行导入解析 if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } //如果元素节点是<Alias>别名元素,进行别名解析 else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } // 普通Bean 。进行解析 else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } }
三种不同情况,分别解析,(产生一个疑问,那Spring配置文件中其他的标签如何加载???)
// import protected void importBeanDefinitionResource(Element ele) { //获取给定的导入元素的location属性 String location = ele.getAttribute(RESOURCE_ATTRIBUTE); //如果导入元素的location属性值为空,则没有导入任何资源,直接返回 if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; } //使用系统变量值解析location属性值 location = SystemPropertyUtils.resolvePlaceholders(location); Set<Resource> actualResources = new LinkedHashSet<Resource>(4); //标识给定的导入元素的location是否是绝对路径 boolean absoluteLocation = false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { //给定的导入元素的location不是绝对路径 } //给定的导入元素的location是绝对路径 if (absoluteLocation) { try { //使用资源读入器加载给定路径的Bean定义资源 int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException ex) { getReaderContext().error( "Failed to import bean definitions from URL location [" + location + "]", ele, ex); } } else { //给定的导入元素的location是相对路径 try { int importCount; //将给定导入元素的location封装为相对路径资源 Resource relativeResource = getReaderContext().getResource().createRelative(location); //封装的相对路径资源存在 if (relativeResource.exists()) { //使用资源读入器加载Bean定义资源 importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } //封装的相对路径资源不存在 else { //获取Spring IoC容器资源读入器的基本路径 String baseLocation = getReaderContext().getResource().getURL().toString(); //根据Spring IoC容器资源读入器的基本路径加载给定导入 //路径的资源 importCount = getReaderContext().getReader().loadBeanDefinitions( StringUtils.applyRelativePath(baseLocation, location), actualResources); } if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]"); } } catch (IOException ex) { getReaderContext().error("Failed to resolve current resource location", ele, ex); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, ex); } } Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]); //在解析完<Import>元素之后,发送容器导入其他资源处理完成事件 getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); } // Alias //解析<Alias>别名元素,为Bean向Spring IoC容器注册别名 protected void processAliasRegistration(Element ele) { //获取<Alias>别名元素中name的属性值 String name = ele.getAttribute(NAME_ATTRIBUTE); //获取<Alias>别名元素中alias的属性值 String alias = ele.getAttribute(ALIAS_ATTRIBUTE); boolean valid = true; //<alias>别名元素的name属性值为空 if (!StringUtils.hasText(name)) { getReaderContext().error("Name must not be empty", ele); valid = false; } //<alias>别名元素的alias属性值为空 if (!StringUtils.hasText(alias)) { getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) { try { //向容器的资源读入器注册别名 getReaderContext().getRegistry().registerAlias(name, alias); } catch (Exception ex) { getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, ex); } //在解析完<Alias>元素之后,发送容器别名处理完成事件 getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); } } /////// 解析Bean //解析Bean定义资源Document对象的普通元素 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类 //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { //向Spring IoC容器注册解析得到的Bean定义,这是Bean定义向IoC容器注册的入口 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } //在完成向Spring IoC容器注册解析得到的Bean定义之后,发送注册事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
对于import 这个引入其他配置文件的标签的处理思路是:
先验证这个链接是否正确,然后定位这个资源,如果这个资源合法最后载入这一个资源,并发送处理完成事件
最重要的就是对于Bean的解析了调用这个方法开始解析: BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
// 加载Bean 类型的Element 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()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
加载类名,ID等主要的属性
下面进入BeanDefinitionParserDelegate类中的方法
// 加载过程 ////解析Bean定义资源文件中的<Bean>元素,这个方法中主要处理<Bean>元素的id,name public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List aliases = new ArrayList(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = (String) 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>元素中配置的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); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. 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; }
加载完主要信息,开始加载其他Element标签的信息
/详细加载Bean中的其他Element public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { this.parseState.push(new BeanEntry(beanName)); //创建 BeanDefinition 根据 Class。并设置classLoader 和parent AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition( parent, className, this.readerContext.getBeanClassLoader()); //scope属性 if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { // Spring 2.x "scope" attribute bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { error("Specify either 'scope' or 'singleton', not both", ele); } } // SINGLETON else if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { // Spring 1.x "singleton" attribute bd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ? BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE); } else if (containingBean != null) { // Take default from containing bean in case of an inner bean definition. bd.setScope(containingBean.getScope()); } // ABSTRACT if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } // lazyInit String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit) && bd.isSingleton()) { // Just apply default to singletons, as lazy-init has no meaning for prototypes. lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); // AUTOWIRE String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); // DEPENDENCY String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE); bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); // DEPENDS if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, BEAN_NAME_DELIMITERS)); } // AUTOWIRE_CANDIDATE String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); // DEFAULT_VALUE if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) { String candidatePattern = this.defaults.getAutowireCandidates(); if (candidatePattern != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } else { bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); } if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); } // INIT_METHOD if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) { String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE); if (!"".equals(initMethodName)) { bd.setInitMethodName(initMethodName); } } else { if (this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } } if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) { String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); if (!"".equals(destroyMethodName)) { bd.setDestroyMethodName(destroyMethodName); } } else { if (this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } } if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // 解析构造方法 parseConstructorArgElements(ele, bd); // property属性 parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); //为当前解析的Bean设置所需的资源和依赖对象 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; }
BeanDefinitionReaderUtils 里面加载了classLoader parent等属性
//BeanDefinitionReaderUtils public static AbstractBeanDefinition createBeanDefinition( String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setParentName(parentName); if (className != null) { if (classLoader != null) { bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { bd.setBeanClassName(className); } } return bd; }
下面就是解析构造函数的具体实现了
/** * Parse constructor-arg sub-elements of the given bean element. */ public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && DomUtils.nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) { parseConstructorArgElement((Element) node, bd); } } }
解析Property的实现
/** * Parse property sub-elements of the given bean element. */ public void parsePropertyElements(Element beanEle, BeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); //遍历每一个节点 for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && DomUtils.nodeNameEquals(node, PROPERTY_ELEMENT)) { //分别解析每一个property节点 parsePropertyElement((Element) node, bd); } } }
对每个property节点分别解析
/** * Parse a property element. */ public void parsePropertyElement(Element ele, BeanDefinition bd) { String propertyName = ele.getAttribute(NAME_ATTRIBUTE);//获取名称 if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName));//放入栈中 try { if (bd.getPropertyValues().contains(propertyName)) {//如果有同名元素,不解析 error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } Object val = parsePropertyValue(ele, bd, propertyName);//val 为解析得到的值 PropertyValue pv = new PropertyValue(propertyName, val);//放入propertyValue中, parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv);<span style="font-family: Arial, Helvetica, sans-serif;">//设置到BeanDefinitionHolder中</span> } finally { this.parseState.pop(); } }
取得property元素的值,也许是个list或者其他的
/** * Get the value of a property element. May be a list etc. * Also used for constructor arguments, "propertyName" being null in this case. */ public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // Should only have one child element: ref, value, list, etc. NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { if (nl.item(i) instanceof Element) { Element candidateEle = (Element) nl.item(i); if (DomUtils.nodeNameEquals(candidateEle, DESCRIPTION_ELEMENT) || DomUtils.nodeNameEquals(candidateEle, META_ELEMENT)) { // Keep going: we don't use these values for now. } else { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = candidateEle; } } } } <span style="white-space:pre"> </span>//不能同时拥有ref或者value属性 boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } <span style="white-space:pre"> </span>//ref类型 if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE);//获取元素名字 if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName);//创建RuntimeBeanReference 封装ref信息 ref.setSource(extractSource(ele));<span style="font-family: Arial, Helvetica, sans-serif;">//是一个指向运行时所依赖对象的引用 </span> return ref; } else if (hasValueAttribute) {//value类型 TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; }//如果有子属性,继续解析 例如List Map 等 else if (subElement != null) { return parsePropertySubElement(subElement, bd); } else { // Neither child element nor "ref" or "value" attribute found. error(elementName + " must specify a ref or value", ele); return null; } }
通过对上述源码的分析,我们可以了解在Spring配置文件中,<Bean>元素中<property>元素的相关配置是如何处理的:
a. ref被封装为指向依赖对象一个引用。
b.value配置都会封装成一个字符串类型的对象。
c.ref和value都通过“解析的数据类型属性值.setSource(extractSource(ele));”方法将属性值/引用与所引用的属性关联起来。
在方法的最后对于<property>元素的子元素通过parsePropertySubElement 方法解析,我们继续分析该方法的源码,了解其解析过程。
6.解析<property>元素的子元素:
在BeanDefinitionParserDelegate类中的parsePropertySubElement方法对<property>中的子元素解析,源码如下:
//解析<property>元素中ref,value或者集合等子元素 public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { //如果<property>没有使用Spring默认的命名空间,则使用用户自定义的规则解析//内嵌元素 if (!isDefaultNamespace(ele)) { return parseNestedCustomElement(ele, bd); } //如果子元素是bean,则使用解析<Bean>元素的方法解析 else if (nodeNameEquals(ele, BEAN_ELEMENT)) { BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } //如果子元素是ref,ref中只能有以下3个属性:bean、local、parent else if (nodeNameEquals(ele, REF_ELEMENT)) { //获取<property>元素中的bean属性值,引用其他解析的Bean的名称 //可以不再同一个Spring配置文件中,具体请参考Spring对ref的配置规则 String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength(refName)) { //获取<property>元素中的local属性值,引用同一个Xml文件中配置 //的Bean的id,local和ref不同,local只能引用同一个配置文件中的Bean refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { //获取<property>元素中parent属性值,引用父级容器中的Bean refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); toParent = true; if (!StringUtils.hasLength(refName)) { error("'bean', 'local' or 'parent' is required for <ref> element", ele); return null; } } } //没有配置ref的目标属性值 if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); return null; } //创建ref类型数据,指向被引用的对象 RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); //设置引用类型值是被当前子元素所引用 ref.setSource(extractSource(ele)); return ref; } //如果子元素是<idref>,使用解析ref元素的方法解析 else if (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement(ele); } //如果子元素是<value>,使用解析value元素的方法解析 else if (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } //如果子元素是null,为<property>设置一个封装null值的字符串数据 else if (nodeNameEquals(ele, NULL_ELEMENT)) { TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } //如果子元素是<array>,使用解析array集合子元素的方法解析 else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement(ele, bd); } //如果子元素是<list>,使用解析list集合子元素的方法解析 else if (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement(ele, bd); } //如果子元素是<set>,使用解析set集合子元素的方法解析 else if (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement(ele, bd); } //如果子元素是<map>,使用解析map集合子元素的方法解析 else if (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement(ele, bd); } //如果子元素是<props>,使用解析props集合子元素的方法解析 else if (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement(ele); } //既不是ref,又不是value,也不是集合,则子元素配置错误,返回null else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } }
解析List
//解析<list>集合子元素 public List parseListElement(Element collectionEle, BeanDefinition bd) { //获取<list>元素中的value-type属性,即获取集合元素的数据类型 String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE); //获取<list>集合元素中的所有子节点 NodeList nl = collectionEle.getChildNodes(); //Spring中将List封装为ManagedList ManagedList<Object> target = new ManagedList<Object>(nl.getLength()); target.setSource(extractSource(collectionEle)); //设置集合目标数据类型 target.setElementTypeName(defaultElementType); target.setMergeEnabled(parseMergeAttribute(collectionEle)); //具体的<list>元素解析 parseCollectionElements(nl, target, bd, defaultElementType); return target; } //具体解析<list>集合元素,<array>、<list>和<set>都使用该方法解析 protected void parseCollectionElements( NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) { //遍历集合所有节点 for (int i = 0; i < elementNodes.getLength(); i++) { Node node = elementNodes.item(i); //节点不是description节点 if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) { //将解析的元素加入集合中,递归调用下一个子元素 target.add(parsePropertySubElement((Element) node, bd, defaultElementType)); } } }
经过对Spring Bean定义资源文件转换的Document对象中的元素层层解析,Spring IoC现在已经将XML形式定义的Bean定义资源文件转换为Spring IoC所识别的数据结构——BeanDefinition,它是Bean定义资源文件中配置的POJO对象在Spring IoC容器中的映射,我们可以通过AbstractBeanDefinition为入口,荣IoC容器进行索引、查询和操作。
通过Spring IoC容器对Bean定义资源的解析后,IoC容器大致完成了管理Bean对象的准备工作,即初始化过程,但是最为重要的依赖注入还没有发生,现在在IoC容器中BeanDefinition存储的只是一些静态信息,接下来需要向容器注册Bean定义信息才能全部完成IoC容器的初始化过程。
注册的过程就是将处理好的BeanDefinition加入到 BeanDefinitionMap中
处理注册的代码在DefaultListableBeanFactory中
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "'beanName' must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); 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); resetBeanDefinition(beanName); } }
</pre><div style="top:2271px"><p>而载入和注册都在这一个函数中,DefaultBeanDefinitionDocumentReader类的方法:<pre name="code" class="java">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()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
相关文章推荐
- Java同步器框架剖析
- java多线程3--synchronized
- 定制Eclipse IDE之功能篇(二)
- java中的equals()方法
- windows命令行中java和javac、javap使用详解(java编译命令)(转)
- Java学习二:Javac Java的学习(原创)
- Java_Web三大框架之Hibernate+jsp+selvect+HQL注册用户
- 初学JAVA简谈字符串String存储的以及字符串值的比较(==运算符以及equals())
- Java 提取文件编码
- IO流学习日志
- Spring集成JPA后,报“Not an managed type: class x.x.x"
- eclipse 访问控制图标详解
- java获取汉字拼音首字母
- eclipse package explorer视图中怎么让default package不显示?
- java 伪随机数安全性
- 使用无插件的eclipse版本进行J2EE开发所需要下载的插件
- java多线程之 ---- 线程同步
- 集成Dubbo服务(Spring)
- java中return的作用
- Java文件实时监控Commons-io