Spring源码解析之标签的解析上篇
来源:互联网 发布:足彩大数据分析哪里看 编辑:程序博客网 时间:2024/06/05 12:47
阅读须知
研究了半天markdown也没发现怎么为代码块中的重点代码做特殊标记,所以这里使用//单行注释做代码的简单注释,而/**/多行注释的代码注释的同时会做深入分析,同时为了避免篇幅过长,删掉了Spring原来的注释和空行,建议配合Spring源代码进行阅读,本文对应的Spring源码的版本为4.3.8。
正文
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
这句代码相信大家都很熟悉,我们用这句代码加载配置文件来初始化Spring,下面我们就以这句代码作为入口来看一下Spring初始化都做了哪些工作:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException { /*调用重载构造方法*/ this(new String[] {configLocation}, true, null);}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); //设置父级环境对象,这里传入的是null setConfigLocations(configLocations); /*设置配置文件路径*/ if (refresh) { refresh(); /*刷新环境*/ }}
public void setConfigLocations(String... locations) { if (locations != null) { Assert.noNullElements(locations, "Config locations must not be null"); this.configLocations = new String[locations.length]; for (int i = 0; i < locations.length; i++) { //解析配置文件路径中的特殊符号(如${}等)并设置配置文件路径 this.configLocations[i] = resolvePath(locations[i]).trim(); } } else { this.configLocations = null; }}
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { prepareRefresh(); /*为刷新做准备工作*/ ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); /*初始化BeanFactory,并解析配置*/ prepareBeanFactory(beanFactory); /*为BeanFactory填充功能*/ try { /*子类扩展对BeanFactory进行额外处理*/ postProcessBeanFactory(beanFactory); /*调用注册的BeanFactoryPostProcessors的postProcessBeanFactory方法*/ invokeBeanFactoryPostProcessors(beanFactory); /*注册BeanPostProcessors*/ registerBeanPostProcessors(beanFactory); /*初始化MessageSource,用于国际化处理*/ initMessageSource(); /*初始化应用事件广播器*/ initApplicationEventMulticaster(); /*子类扩展初始化一些个性化的bean*/ onRefresh(); /*找到ApplicationListener bean,并注册*/ registerListeners(); /*初始化剩下的所有非lazy-init的单例bean*/ finishBeanFactoryInitialization(beanFactory); /*初始化LifecycleProcessor(生命周期处理器),发步对应的事件通知,如果配置了JMX,则注册MBean*/ finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } /*销毁已经创建的单例Bean*/ destroyBeans(); /*重置active标记为false*/ cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } }}
这个方法包含的功能非常多,本文只会讲解前两步,剩余部分会在后续的文章中一一阐述。
protected void prepareRefresh() { //设置初始化开始时间 this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } initPropertySources(); //初始化设置属性,留给子类扩展,默认空实现 //校验必须的属性,用户也可以根据个性化需求扩展必要属性的校验 getEnvironment().validateRequiredProperties(); this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();}
在进入下面的分析之前简单介绍一下BeanFactory,BeanFactory提供Spring的IoC功能的基础,字面理解就是bean工厂,用来定义和创建bean。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); /*刷新BeanFactory*/ ConfigurableListableBeanFactory beanFactory = getBeanFactory(); //获取BeanFactory if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory;}
protected final void refreshBeanFactory() throws BeansException { //如果有BeanFactory,则销毁已经创建的bean并关闭掉BeanFactory(将其置为null) if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //创建BeanFactory(DefaultListableBeanFactory) DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); //设置序列化id customizeBeanFactory(beanFactory); /*定制BeanFactory*/ loadBeanDefinitions(beanFactory); /*加载BeanDefinition*/ synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); }}
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { //设置是否允许覆盖同名称不同定义的对象 if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } //设置是否允许bean之间的循环依赖 if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); }}
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)); initBeanDefinitionReader(beanDefinitionReader); /*加载BeanDefinition*/ loadBeanDefinitions(beanDefinitionReader); }
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { /*加载BeanDefinition*/ reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { /*加载BeanDefinition*/ reader.loadBeanDefinitions(configLocations); }}
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int counter = 0; for (String location : locations) { /*加载BeanDefinition*/ counter += loadBeanDefinitions(location); } return counter;}
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { /*加载BeanDefinition*/ return loadBeanDefinitions(location, null);}
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) { try { //根据配置文件路径获取Resource Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); /*加载BeanDefinition*/ 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 { 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; }}
在为XmlBeanDefinitionReader设置资源加载器时传入了this,而ClassPathXmlApplicationContext间接实现了ResourcePatternResolver,满足if条件判断进入第一个分支流程。这里提到了Resource,Spring用Resource封装了各种文件,例如FileSystemResource、ClassPathResource、UrlResource、InputStreamResource、ByteArrayResource等资源,从命名上就可以看出,我们可以从这些Resource中拿到资源的URL、文件流、字节数组等。
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { /*加载BeanDefinition*/ counter += loadBeanDefinitions(resource); } return counter;}
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { /*加载BeanDefinition*/ return loadBeanDefinitions(new EncodedResource(resource));}
这里用EncodedResource封装了Resource目的是为了当设置了编码属性的时候Spring使用相应的编码作为输入流的编码。
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 { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { //设置字符编码 inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); /*加载BeanDefinition*/ } 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(); } }}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { /*加载Document*/ Document doc = doLoadDocument(inputSource, resource); /*注册BeanDefinition*/ 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); }}
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { /*获取XML验证模式,加载Document*/ return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, getValidationModeForResource(resource), isNamespaceAware());}
这里会获取XML配置文件的验证模式,也就是验证XSD或者DTD,判断的依据就是配置文件的内容是否包含DOCTYPE,如果包含就是DTD,否则就是XSD。获取Document就是解析XML的操作了,没有什么特别的,这里有必要提一下EntityResolver,在校验XML时,首先需要读取XML文档声明获取DTD声明,默认是通过网络进行下载DTD声明,网络下载比较慢而且存在中断的风险,EntityResolver就是用来帮助程序寻找DTD声明的,根据用户声明校验模式的不同,在本地寻找并加载对应的DTD或XSD文件。获取到Document后,就可以开始注册BeanDefinition了:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); 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"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); /*注册BeanDefinition*/}
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); //profile属性的处理 if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } preProcessXml(root); //解析前置处理,由子类扩展 /*解析BeanDefinition*/ parseBeanDefinitions(root, this.delegate); postProcessXml(root); //解析后置处理,由子类扩展 this.delegate = parent;}
这里提到了profile属性,简单说明一下作用,我们可以通过这个属性将开发、测试、生产等环境的配置区分开来,实际应用中并不是很常用。
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)) { /*默认标签的解析*/ parseDefaultElement(ele, delegate); } else { /*自定义标签的解析*/ delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); /*自定义标签的解析*/ }}
这里提到了默认标签和自定义标签,Spring用节点的命名空间来判断是默认还是自定义,具体的,如果节点的命名空间为http://www.Springframework.org/schema/beans就认为是默认,否则就认为是自定义。接下来我们来看默认标签和自定义标签的解析,首先来看默认标签的解析:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); /*import标签解析*/ } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); /*alias标签解析*/ } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); /*bean标签解析*/ } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { doRegisterBeanDefinitions(ele); /*beans标签解析*/ }}
这里我们看到了我们在使用Spring时经常配置的4个标签的解析,也就是说,这4个标签是Spring的默认标签,其他都是自定义标签,其中,beans标签的解析与配置文件根节点的解析是一样的,会递归调用再次进入doRegisterBeanDefinitions方法,另外三个标签我们先看最复杂的bean标签的解析:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { /*解析bean标签的属性和子元素,构建BeanDefinition并封装到BeanDefinitionHolder中*/ BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { /*如果bean标签含有自定义子标签,则需要按照自定义标签的解析方式继续解析子标签*/ bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { /*注册BeanDefinition*/ BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } //将bean注册完成事件通知到相关的监听器 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); }}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { /*解析BeanDefinition*/ return parseBeanDefinitionElement(ele, null);}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); //id属性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); //name属性 List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); //以,或;分割name aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; 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); } /*解析BeanDefinition*/ AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { //如果没有设置beanName,则按照Spring的规则生成一个beanName if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { 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 (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;}
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { //属性 className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { //parent属性 parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); /*创建BeanDefinition*/ parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); /*解析bean的属性*/ bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); /*解析元数据*/ parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); /*解析lookup-method*/ parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); /*解析replaced-method*/ parseConstructorArgElements(ele, bd); /*解析构造方法*/ parsePropertyElements(ele, bd); /*解析property子元素*/ parseQualifierElements(ele, bd); /*解析qualifier子元素*/ 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;}
protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException { /*创建BeanDefinition*/ return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader());}
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;}
这里首先创建了BeanDefinition,并为其设置了beanClass或者className,BeanDefinition字面翻译为bean的定义,我们可以把它理解为bean标签的java代码实现,里面保存了我们配置的各种bean的属性。
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { //Spring4.0已经不支持设置singleton属性,用scope代替 if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { //设置scope属性 bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); } else if (containingBean != null) { //如果是内部的BeanDefinition并且没有设置scope,则继承父BeanDefinition的scope bd.setScope(containingBean.getScope()); } if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { //设置abstract属性 bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { //设置lazy-init属性 lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); //设置autowire属性 String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE); //设置dependency-check属性 bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); //设置depends-on属性 } String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); 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)); //设置autowire-candidate属性 } } else { bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); } if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); //设置primary属性 } //设置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); } } //设置destory-method属性 if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) { String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); bd.setDestroyMethodName(destroyMethodName); } else { if (this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } } //设置factory-method属性 if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } //设置factory-bean属性 if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } return bd;}
这里我们看到了各种常见或者不常见的属性的解析和设置,有兴趣的读者可以查阅Spring官方文档了解一下这些属性的应用,以便于更好的理解。
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) { NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) { //meta子元素的解析 Element metaElement = (Element) node; //key属性 String key = metaElement.getAttribute(KEY_ATTRIBUTE); String value = metaElement.getAttribute(VALUE_ATTRIBUTE); //value属性 BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value); attribute.setSource(extractSource(metaElement)); attributeAccessor.addMetadataAttribute(attribute); } }}
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) { //lookup-method子元素的解析 Element ele = (Element) node; //name属性 String methodName = ele.getAttribute(NAME_ATTRIBUTE); //bean属性 String beanRef = ele.getAttribute(BEAN_ELEMENT); LookupOverride override = new LookupOverride(methodName, beanRef); override.setSource(extractSource(ele)); overrides.addOverride(override); } }}
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) { //replaced-method子元素解析 Element replacedMethodEle = (Element) node; String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE); //name属性 String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE); //replacer属性 ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT); //replaced-method子元素arg-type的解析 for (Element argTypeEle : argTypeEles) { String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE); //match属性 match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle)); if (StringUtils.hasText(match)) { replaceOverride.addTypeIdentifier(match); } } replaceOverride.setSource(extractSource(replacedMethodEle)); overrides.addOverride(replaceOverride); } }}
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 (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) { /*constructor-arg子元素的解析*/ parseConstructorArgElement((Element) node, bd); } }}
public void parseConstructorArgElement(Element ele, BeanDefinition bd) { //index属性 String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE); //type属性 String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE); //name属性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(indexAttr)) { try { int index = Integer.parseInt(indexAttr); if (index < 0) { error("'index' cannot be lower than 0", ele); } else { try { this.parseState.push(new ConstructorArgumentEntry(index)); Object value = parsePropertyValue(ele, bd, null); /*解析value属性、ref属性和子元素*/ ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { //重复指定相同的index报错 error("Ambiguous constructor-arg entries for index " + index, ele); } else { bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); //设置构造方法的index和参数值 } } finally { this.parseState.pop(); } } } catch (NumberFormatException ex) { error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); } } else { //没有index属性自动匹配 try { this.parseState.push(new ConstructorArgumentEntry()); Object value = parsePropertyValue(ele, bd, null); ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); if (StringUtils.hasLength(typeAttr)) { valueHolder.setType(typeAttr); } if (StringUtils.hasLength(nameAttr)) { valueHolder.setName(nameAttr); } valueHolder.setSource(extractSource(ele)); bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); //设置构造方法的参数值 } finally { this.parseState.pop(); } }}
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //meta和description子元素不处理,其他子元素只能有一个 if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); //是否含有ref属性 boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); //是否含有value属性 //value、ref、子元素只能有一个 if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } //根据配置返回ref、value、子元素中的一个作为属性的值 if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { /*解析子元素*/ return parsePropertySubElement(subElement, bd); } else { error(elementName + " must specify a ref or value", ele); return null; }}
public Object parsePropertySubElement(Element ele, BeanDefinition bd) { /*解析子元素*/ return parsePropertySubElement(ele, bd, null);}
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { if (!isDefaultNamespace(ele)) { //自定义元素的解析 return parseNestedCustomElement(ele, bd); } else if (nodeNameEquals(ele, BEAN_ELEMENT)) { //bean子元素解析 BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, REF_ELEMENT)) { //ref子元素解析 String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength(refName)) { refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { 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; } } } if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); return null; } RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } else if (nodeNameEquals(ele, IDREF_ELEMENT)) { //idref子元素解析 return parseIdRefElement(ele); } else if (nodeNameEquals(ele, VALUE_ELEMENT)) { //value子元素解析 return parseValueElement(ele, defaultValueType); } else if (nodeNameEquals(ele, NULL_ELEMENT)) { //null子元素解析 TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { //array子元素解析 return parseArrayElement(ele, bd); } else if (nodeNameEquals(ele, LIST_ELEMENT)) { //list子元素解析 return parseListElement(ele, bd); } else if (nodeNameEquals(ele, SET_ELEMENT)) { //set子元素解析 return parseSetElement(ele, bd); } else if (nodeNameEquals(ele, MAP_ELEMENT)) { //map子元素解析 return parseMapElement(ele, bd); } else if (nodeNameEquals(ele, PROPS_ELEMENT)) { //props子元素解析 return parsePropsElement(ele); } else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; }}
这里就是各种类型子标签的解析,例如如果子标签是bean标签的话,就用解析bean标签的流程再次将子标签解析一遍,自定义标签的解析我们会在后面进行详细阐述,其他类型的子标签就不一一赘述了,有兴趣的读者可以自行深入研究。构造方法的解析就到这,下面是子元素property的解析:
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 (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) { /*解析property子元素*/ parsePropertyElement((Element) node, bd); } }}
public void parsePropertyElement(Element ele, BeanDefinition bd) { //name属性 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 { //同一个bean的propertyName不允许重复 if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } //解析ref、value和子元素,上文有提到过 Object val = parsePropertyValue(ele, bd, propertyName); PropertyValue pv = new PropertyValue(propertyName, val); parseMetaElements(ele, pv); //解析meta子元素,上文提到过 pv.setSource(extractSource(ele)); //将property属性添加到BeanDefinition的propertyValues属性中 bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); }}
qualifier子元素的解析:
public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) { /*解析qualifier子元素*/ parseQualifierElement((Element) node, bd); } }}
public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) { //type属性 String typeName = ele.getAttribute(TYPE_ATTRIBUTE); if (!StringUtils.hasLength(typeName)) { error("Tag 'qualifier' must have a 'type' attribute", ele); return; } this.parseState.push(new QualifierEntry(typeName)); try { AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName); qualifier.setSource(extractSource(ele)); //value属性 String value = ele.getAttribute(VALUE_ATTRIBUTE); if (StringUtils.hasLength(value)) { qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value); } NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) { //attribute子元素的解析 Element attributeEle = (Element) node; String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE); //key属性 String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE); //value属性 if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) { BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue); attribute.setSource(extractSource(attributeEle)); qualifier.addMetadataAttribute(attribute); } else { //key和value必须同时存在,否则报错 error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle); return; } } } bd.addQualifier(qualifier); } finally { this.parseState.pop(); }}
到这里我们完成了bean标签解析的第一步,下一步是对子标签是自定义标签情况进行解析,如果已经忘了从哪里进来的请回看processBeanDefinition方法。不知道大家是否有疑问,上文中我们已经提到了根据命名空间来区分默认标签的解析和自定义标签的解析,这里直接走自定义标签解析的那个分支来处理就可以了,为什么会有单独的一段逻辑呢?这里我们提到的自定义标签是子标签,也就是说它是作为bean的属性存在的,所以要单独进行解析:
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) { /*如果子标签是自定义子标签,则需要按照自定义标签解析的形式进行修饰*/ return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);}
public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) { BeanDefinitionHolder finalDefinition = definitionHolder; NamedNodeMap attributes = ele.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node node = attributes.item(i); finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); /*遍历所有属性,判断是否需要修饰*/ } NodeList children = ele.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); /*遍历所有子元素,判断是否需要修饰*/ } } return finalDefinition;}
public BeanDefinitionHolder decorateIfRequired( Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(node); if (!isDefaultNamespace(namespaceUri)) { //如果不是默认命名空间,就是自定义标签 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); //根据命名空间获取NamespaceHandler if (handler != null) { //修饰 return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd)); } else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node); } else { if (logger.isDebugEnabled()) { logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]"); } } } return originalDef;}
这里根据自定义标签的命名空间获取对应NamespaceHandler进行修饰,这部分内容我们会在后面自定义标签的解析中进行详细阐述。接下来就是BeanDefinition的注册过程了:
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); /*注册BeanDefinition*/ registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { /*注册alias别名*/ registry.registerAlias(beanName, alias); } }}
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 { //这里校验的是我们在配置lookup-method和replaced-method时产生的MethodOverrides和factory-method是否同时存在,同时存在会报错,并校验MethodOverrides中的方法是否真正存在 ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { //如果有相同的beanName存在并且设置了不允许bean覆盖就会报错 if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } //从这往下几个分支的判断都是根据不同情况记录日志 else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { //如果已经开始创建bean if (hasBeanCreationStarted()) { //beanDefinitionMap是公共属性,对其修改需要加锁 synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); //这里new一个新的集合重新添加并赋值给beanDefinitionNames个人理解是为了固定集合的长度 List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { //如果手工注册的单例beanName集合包含当前beanName则移除掉 Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { //如果bean还没开始创建,则直接加入对应的缓存即可 this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); //重置beanName对应的缓存 }}
public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); if (alias.equals(name)) { //如果alias和beanName相同则删除对应的alias this.aliasMap.remove(alias); } else { String registeredName = this.aliasMap.get(alias); if (registeredName != null) { if (registeredName.equals(name)) { return; //如果已经存在别名映射并和本次添加的值相同则无需再次添加 } if (!allowAliasOverriding()) { //如果设置了不允许alias覆盖则报错 throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } } checkForAliasCircle(name, alias); //检查alias循环映射 this.aliasMap.put(alias, name); }}
到这里,整个bean标签的解析的注册就完成了,下面我们来看alias标签的解析:
protected void processAliasRegistration(Element ele) { //name属性 String name = ele.getAttribute(NAME_ATTRIBUTE); //alias属性 String alias = ele.getAttribute(ALIAS_ATTRIBUTE); boolean valid = true; if (!StringUtils.hasText(name)) { getReaderContext().error("Name must not be empty", ele); valid = false; } if (!StringUtils.hasText(alias)) { getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) { try { getReaderContext().getRegistry().registerAlias(name, alias); //注册alias } catch (Exception ex) { getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, ex); } getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); }}
alias标签的解析和注册与之前bean中name属性分割后产生的的alias数组的解析是同样的逻辑,不再赘述。下面我们来看import标签的解析:
protected void importBeanDefinitionResource(Element ele) { //resource属性 String location = ele.getAttribute(RESOURCE_ATTRIBUTE); if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; } location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); //对特殊符号如${}的解析 Set<Resource> actualResources = new LinkedHashSet<Resource>(4); boolean absoluteLocation = false; try { //判断是绝对路径还是相对路径 absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { } if (absoluteLocation) { try { 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 { try { int importCount; //尝试获取相对路径对应的资源 Resource relativeResource = getReaderContext().getResource().createRelative(location); if (relativeResource.exists()) { //存在则直接解析 importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { //不存在则拼接根路径尝试获取配置文件进行解析 String baseLocation = getReaderContext().getResource().getURL().toString(); 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()]); getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));}
import标签的解析就是根据resource属性配置的路径获取到对应的资源然后按照上文解析标签的流程进行解析。Spring在解析标签完成之后会将对应标签的解析完成事件通知对应的监听器,因为Spring本身只实现了一个默认的空监听器,所以我们可以根据自身的个性化需求进行扩展实现,这里就不多赘述了。到这里,整个默认标签的解析就完成了,下篇文章会继续分析Spring自定义标签解析的源码。
- Spring源码解析之标签的解析上篇
- Spring源码解析之默认标签的解析(一)
- Spring源码解析之标签的解析下篇
- Spring源码解析-默认标签的解析
- Spring源码解析-自定义标签的解析
- 《Spring源码深度解析》阅读笔记5-默认标签的解析之bean标签的解析及注册
- kafka源码解析之十二KafkaController(上篇)
- spring源码-2-xml标签的解析
- Spring源码解析之二 ------ 自定义标签的解析和注册(IOC的第一步)
- spring源码深度解析(笔记二)--默认标签的解析
- spring源码深度解析(笔记三)--自定义标签的解析
- Spring Framework源码(六):Spring AOP之解析标签
- Spring 源码解析 ---- 自定义标签
- Spring源码分析:AOP源码解析(上篇)
- Spring源码分析:AOP源码解析(上篇)
- Spring源码解析-自定义标签解析
- spring源代码之标签的解析
- Spring Security4.0.3源码分析之http标签解析
- 设置VMWare桥接模式静态IP
- Intellij IDEA--can't use subversion command line client : svn
- 读《哈默手稿》
- [转] Git中.gitignore的配置语法
- DataNode启动流程源码分析
- Spring源码解析之标签的解析上篇
- Oracle Spacial(空间数据库)GEOMETRY示例
- 网易有道2017内推编程题:洗牌 [python]
- 19.开源项目--分支管理
- 初识hadoop
- okhttp二次封装+单例模式+拦截器
- java中根据手机号获取手机号归属地
- 删除和添加索引,为什么要先加后删
- QWidget 设置背景色