看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead

代码过宽,可以shift + 鼠标滚轮 左右滑动查看

AbstractBeanDefinitionReader类中loadBeanDefinitions方法,该方法会对DOM文档对象进行解析,生成BeanDefinition对象,这篇文章只讲这个方法。

  1. /**
  2. * Load bean definitions from the specified resources.
  3. * @param resources the resource descriptors 资源处理器,也叫做资源描述符
  4. * @return the number of bean definitions found 返回发现的bean definition数量
  5. *
  6. * 从指定资源中加载bean definitions
  7. */
  8. @Override
  9. public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
  10. Assert.notNull(resources, "Resource array must not be null");
  11. int counter = 0;
  12. //因为我的web.xml中配置contextConfigLocation不管classpath前缀还是后半部分
  13. //都没有使用 * 或者 ?等表达式,所以只有一个Resource--资源描述符,或者
  14. //称作资源处理器
  15. for (Resource resource : resources) {
  16. //调用的子类XmlBeanDefinitionReader方法,进入查看
  17. counter += loadBeanDefinitions(resource);
  18. }
  19. return counter;
  20. }
  21. /**
  22. * 此方法在AbstractBeanDefinitionReader的子类XmlBeanDefinitionReader中
  23. *
  24. * Load bean definitions from the specified XML file.
  25. * 从指定的xml文件中加载bean definitions
  26. */
  27. @Override
  28. public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
  29. return loadBeanDefinitions(new EncodedResource(resource));
  30. }
  31. public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
  32. Assert.notNull(encodedResource, "EncodedResource must not be null");
  33. if (logger.isInfoEnabled()) {
  34. logger.info("Loading XML bean definitions from " + encodedResource.getResource());
  35. }
  36. //resourcesCurrentlyBeingLoaded是一个ThreadLocal,里面存放Resource包装类的set集合
  37. Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
  38. if (currentResources == null) {
  39. currentResources = new HashSet<EncodedResource>(4);
  40. this.resourcesCurrentlyBeingLoaded.set(currentResources);
  41. }
  42. //如果set中已有这个元素则返回false,进入该条件抛出异常
  43. if (!currentResources.add(encodedResource)) {
  44. throw new BeanDefinitionStoreException(
  45. //检测到循环加载某个Resource,需要检查导入的definitions
  46. "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
  47. }
  48. try {
  49. InputStream inputStream = encodedResource.getResource().getInputStream();
  50. try {
  51. InputSource inputSource = new InputSource(inputStream);
  52. //没有设置编码集,跳过
  53. if (encodedResource.getEncoding() != null) {
  54. inputSource.setEncoding(encodedResource.getEncoding());
  55. }
  56. //进入这个方法查看
  57. return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
  58. }
  59. finally {
  60. inputStream.close();
  61. }
  62. }
  63. catch (IOException ex) {
  64. throw new BeanDefinitionStoreException(
  65. "IOException parsing XML document from " + encodedResource.getResource(), ex);
  66. }
  67. finally {
  68. //资源加载完毕,移除该Resource
  69. currentResources.remove(encodedResource);
  70. //如果集合中已经没有了其他Resource,移除集合
  71. if (currentResources.isEmpty()) {
  72. this.resourcesCurrentlyBeingLoaded.remove();
  73. }
  74. }
  75. }

doLoadBeanDefinitions(零)

此方法在XmlBeanDefinitionReader类中,分两部分跟踪

  1. /**
  2. * Actually load bean definitions from the specified XML file.
  3. *
  4. * 真正的从指定xml文件中加载bean definitions
  5. */
  6. protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
  7. throws BeanDefinitionStoreException {
  8. try {
  9. //根据不同的xml约束(dtd,xsd等),将xml文件生成对应的文档对象
  10. //1.这个方法里面涉及xml的解析
  11. Document doc = doLoadDocument(inputSource, resource);
  12. //2.主要就是看这个方法,bean definitions的注册
  13. return registerBeanDefinitions(doc, resource);
  14. }
  15. //看下抛出异常的提示,都是项目运行时可能出现的错误
  16. catch (BeanDefinitionStoreException ex) {
  17. throw ex;
  18. }
  19. catch (SAXParseException ex) {
  20. throw new XmlBeanDefinitionStoreException(resource.getDescription(),
  21. "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
  22. }
  23. catch (SAXException ex) {
  24. throw new XmlBeanDefinitionStoreException(resource.getDescription(),
  25. "XML document from " + resource + " is invalid", ex);
  26. }
  27. catch (ParserConfigurationException ex) {
  28. throw new BeanDefinitionStoreException(resource.getDescription(),
  29. "Parser configuration exception parsing XML from " + resource, ex);
  30. }
  31. catch (IOException ex) {
  32. throw new BeanDefinitionStoreException(resource.getDescription(),
  33. "IOException parsing XML document from " + resource, ex);
  34. }
  35. catch (Throwable ex) {
  36. throw new BeanDefinitionStoreException(resource.getDescription(),
  37. "Unexpected exception parsing XML document from " + resource, ex);
  38. }
  39. }

1.doLoadDocument

跟踪标记1的方法

此方法在XmlBeanDefinitionReader类中

  1. //1.这个方法里面涉及xml的解析
  2. Document doc = doLoadDocument(inputSource, resource);
  3. /**
  4. * Actually load the specified document using the configured DocumentLoader.
  5. * @param inputSource the SAX InputSource to read from --从中读取的SAX输入源
  6. * @param resource the resource descriptor for the XML file --xml文件的资源描述符
  7. * @return the DOM Document DOM文档对象
  8. *
  9. * 使用配置好的DocumentLoader文档加载器加载指定的文档
  10. */
  11. protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
  12. return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
  13. getValidationModeForResource(resource), isNamespaceAware());
  14. }

上面方法入参说明一下:

参一

inputSource 由上一层方法传递过来。

参二

getEntityResolver() 方法返回 XmlBeanDefinitionReader 类的 entityResolver 属性。

entityResolver 属性在 loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 方法中被赋值。

  1. beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

this拿的是根web应用上下文,查看ResourceEntityResolver的构造方法

  1. /**
  2. * Create a ResourceEntityResolver for the specified ResourceLoader
  3. * (usually, an ApplicationContext).
  4. * @param resourceLoader the ResourceLoader (or ApplicationContext)
  5. * to load XML entity includes with
  6. *
  7. * 为指定的ResourceLoade(通常是应用上下文)r创建一个ResourceEntityResolver
  8. */
  9. public ResourceEntityResolver(ResourceLoader resourceLoader) {
  10. super(resourceLoader.getClassLoader());
  11. //此处解析器拿到了上下文的引用
  12. this.resourceLoader = resourceLoader;
  13. }

调用了父类构造,再跟进一层

  1. /**
  2. * Create a new DelegatingEntityResolver that delegates to
  3. * a default {@link BeansDtdResolver} and a default {@link PluggableSchemaResolver}.
  4. * <p>Configures the {@link PluggableSchemaResolver} with the supplied
  5. * {@link ClassLoader}.
  6. * @param classLoader the ClassLoader to use for loading
  7. * (can be {@code null}) to use the default ClassLoader)
  8. */
  9. public DelegatingEntityResolver(ClassLoader classLoader) {
  10. //这两个解析器和约束的类型有关,DTD
  11. this.dtdResolver = new BeansDtdResolver();
  12. //可插拔的Schema解析器,拿的上下文的类加载器
  13. this.schemaResolver = new PluggableSchemaResolver(classLoader);
  14. }

参三

再看doLoadDocument方法的另外一个入参 this.errorHandler,这个属性随着XmlBeanDefinitionReader类被初始化而初始化

  1. private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger);

参四

然后是getValidationModeForResource(resource)入参。

  1. /**
  2. * Gets the validation mode for the specified {@link Resource}. If no explicit
  3. * validation mode has been configured then the validation mode is
  4. * {@link #detectValidationMode detected}.
  5. * <p>Override this method if you would like full control over the validation
  6. * mode, even when something other than {@link #VALIDATION_AUTO} was set.
  7. *
  8. * 通过给定Resource给出验证模式。如果没有明确配置验证模式,那么调用detectValidationMode方法去检测。
  9. */
  10. protected int getValidationModeForResource(Resource resource) {
  11. //默认自动验证,为1
  12. int validationModeToUse = getValidationMode();
  13. //如果有给出具体验证方式,则返回结果
  14. if (validationModeToUse != VALIDATION_AUTO) {
  15. return validationModeToUse;
  16. }
  17. //检测验证模式,进入这个方法
  18. int detectedMode = detectValidationMode(resource);
  19. if (detectedMode != VALIDATION_AUTO) {
  20. return detectedMode;
  21. }
  22. // Hmm, we didn't get a clear indication... Let's assume XSD,
  23. // since apparently no DTD declaration has been found up until
  24. // detection stopped (before finding the document's root tag).
  25. // 如果实在不能判断验证模式是那种就使用XSD方式,
  26. // 因为检测完后还是没有发现DTD模式的声明(在查找document的根标签之前)。
  27. // 值为3
  28. return VALIDATION_XSD;
  29. }

进入下面这个方法,这个方法由XmlBeanDefinitionReader实现

  1. int detectedMode = detectValidationMode(resource);
  2. /**
  3. * Detects which kind of validation to perform on the XML file identified
  4. * by the supplied {@link Resource}. If the file has a {@code DOCTYPE}
  5. * definition then DTD validation is used otherwise XSD validation is assumed.
  6. * <p>Override this method if you would like to customize resolution
  7. * of the {@link #VALIDATION_AUTO} mode.
  8. *
  9. * 检测执行xml文件时该用哪种验证方式,这个xml由Resource对象提供
  10. * 如果这个文件有DOCTYPE声明,那么就用DTD验证,否则就假定使用XSD。
  11. * 如果你想要自定义自动验证模式的解决方式,你可以覆盖这个方法
  12. */
  13. protected int detectValidationMode(Resource resource) {
  14. //默认false
  15. if (resource.isOpen()) {
  16. throw new BeanDefinitionStoreException(
  17. "Passed-in Resource [" + resource + "] contains an open stream: " +
  18. "cannot determine validation mode automatically. Either pass in a Resource " +
  19. "that is able to create fresh streams, or explicitly specify the validationMode " +
  20. "on your XmlBeanDefinitionReader instance.");
  21. }
  22. InputStream inputStream;
  23. try {
  24. inputStream = resource.getInputStream();
  25. }
  26. catch (IOException ex) {
  27. throw new BeanDefinitionStoreException(
  28. "Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +
  29. "Did you attempt to load directly from a SAX InputSource without specifying the " +
  30. "validationMode on your XmlBeanDefinitionReader instance?", ex);
  31. }
  32. try {
  33. //进入这个方法查看
  34. return this.validationModeDetector.detectValidationMode(inputStream);
  35. }
  36. catch (IOException ex) {
  37. throw new BeanDefinitionStoreException("Unable to determine validation mode for [" +
  38. resource + "]: an error occurred whilst reading from the InputStream.", ex);
  39. }
  40. }

XmlBeanDefinitionReader的validationModeDetector属性有默认实现

  1. private final XmlValidationModeDetector validationModeDetector = new XmlValidationModeDetector();

validationModeDetector调用detectValidationMode方法

  1. /**
  2. * Detect the validation mode for the XML document in the supplied {@link InputStream}.
  3. * Note that the supplied {@link InputStream} is closed by this method before returning.
  4. *
  5. * 在提供的InputStream中检测XML文档的验证模式
  6. * 注意,提供的InputStream在这个方法return之前会被关闭
  7. */
  8. public int detectValidationMode(InputStream inputStream) throws IOException {
  9. // Peek into the file to look for DOCTYPE.
  10. // 查找文件的DOCTYPE
  11. BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
  12. try {
  13. boolean isDtdValidated = false;
  14. String content;
  15. while ((content = reader.readLine()) != null) {
  16. //读一行字符串就干掉字符串里面的注释,如果全是注释全干掉
  17. //主要为了剥离注释,因为非注释内容要么是DOCTYPE声明要么是文档的根元素对象
  18. content = consumeCommentTokens(content);
  19. //剥离注释后完全没内容就继续循环
  20. if (this.inComment || !StringUtils.hasText(content)) {
  21. continue;
  22. }
  23. //有DOCTYPE声明,就跳出去
  24. if (hasDoctype(content)) {
  25. isDtdValidated = true;
  26. break;
  27. }
  28. //注释不能进去。开头是"<",后面第一个字符是字母,就进入。
  29. //比如'<beans xmlns="http://www.springframework.org/schema/beans"'
  30. //进去后跳出循环
  31. if (hasOpeningTag(content)) {
  32. // End of meaningful data...
  33. break;
  34. }
  35. }
  36. //当遍历到名称空间了也就是"<beans xmlns=...>"还没有DOCTYPE声明,
  37. //那么就判定他为XSD验证
  38. return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
  39. }
  40. catch (CharConversionException ex) {
  41. // Choked on some character encoding...
  42. // Leave the decision up to the caller.
  43. return VALIDATION_AUTO;
  44. }
  45. finally {
  46. //关流
  47. reader.close();
  48. }
  49. }

我这么里用的XSD验证。也就是值为3,传递给loadDocument的入参

参五

最后一个入参,isNamespaceAware()

  1. /**
  2. * Return whether or not the XML parser should be XML namespace aware.
  3. *
  4. * XML解析器是否支持XML名称空间
  5. */
  6. public boolean isNamespaceAware() {
  7. return this.namespaceAware;
  8. }

默认false

看完五个参数后进入正主,loadDocument方法。

  1. return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
  2. getValidationModeForResource(resource), isNamespaceAware());

documentLoader属性默认实现:

  1. private DocumentLoader documentLoader = new DefaultDocumentLoader();

进入DefaultDocumentLoader类的loadDocument方法

  1. /**
  2. * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
  3. * XML parser.
  4. *
  5. * 使用标准JAXP配置XML解析器加载InputSource的Document对象
  6. */
  7. @Override
  8. public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
  9. ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
  10. //创建文档构建器工厂对象,并初始化一些属性
  11. //如果验证模式为XSD,那么强制支持XML名称空间,并加上schema属性
  12. DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
  13. if (logger.isDebugEnabled()) {
  14. logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
  15. }
  16. //创建一个JAXP文档构建器
  17. DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
  18. //按照XML文档解析给定inputSource的内容,然后返回一个新的DOM对象
  19. return builder.parse(inputSource);
  20. }

这样就拿到了Document对象

回到XmlBeanDefinitionReader类的doLoadBeanDefinitions方法

2.registerBeanDefinitions

跟踪标记2的方法

  1. //2.主要就是看这个方法,bean definitions的注册
  2. return registerBeanDefinitions(doc, resource);
  3. /**
  4. * Register the bean definitions contained in the given DOM document.
  5. * Called by {@code loadBeanDefinitions}.
  6. * <p>Creates a new instance of the parser class and invokes
  7. * {@code registerBeanDefinitions} on it.
  8. *
  9. * 注册包含在给定DOM文档对象中的 bean definition
  10. * 被loadBeanDefinitions方法所调用
  11. * 解析class后创建一个新的实例,并调用registerBeanDefinitions方法
  12. */
  13. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
  14. BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
  15. //getRegistry()方法拿的是bean工厂对象,beanDefinition注册在工厂中
  16. //这个方法就是返回已经被注册在工厂中的beanDefinitions数量
  17. int countBefore = getRegistry().getBeanDefinitionCount();
  18. //进入这个方法查看
  19. documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
  20. //返回上个方法真正注册在工厂中的beanDefinition数量
  21. return getRegistry().getBeanDefinitionCount() - countBefore;
  22. }
  23. /**
  24. * 这个方法在刚创建的DefaultBeanDefinitionDocumentReader中
  25. *
  26. * This implementation parses bean definitions according to the "spring-beans" XSD
  27. * (or DTD, historically).
  28. * <p>Opens a DOM Document; then initializes the default settings
  29. * specified at the {@code <beans/>} level; then parses the contained bean definitions.
  30. *
  31. * 根据“spring-beans"的XSD(或者DTD)去解析bean definition
  32. * 打开一个DOM文档,然后初始化在<beans/>层级上指定的默认设置,然后解析包含在其中的bean definitions
  33. */
  34. @Override
  35. public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
  36. //入参时创建的XmlReaderContext对象
  37. this.readerContext = readerContext;
  38. logger.debug("Loading bean definitions");
  39. //拿到了xml文档对象的根元素
  40. Element root = doc.getDocumentElement();
  41. //进入这个方法进行查看
  42. doRegisterBeanDefinitions(root);
  43. }

查看DefaultBeanDefinitionDocumentReader类的doRegisterBeanDefinitions方法。

  1. /**
  2. * Register each bean definition within the given root {@code <beans/>} element.
  3. *
  4. * 在给定的根元素对象<beans/>中,注册每一个bean definition
  5. */
  6. protected void doRegisterBeanDefinitions(Element root) {
  7. // Any nested <beans> elements will cause recursion in this method. In
  8. // order to propagate and preserve <beans> default-* attributes correctly,
  9. // keep track of the current (parent) delegate, which may be null. Create
  10. // the new (child) delegate with a reference to the parent for fallback purposes,
  11. // then ultimately reset this.delegate back to its original (parent) reference.
  12. // this behavior emulates a stack of delegates without actually necessitating one.
  13. // 任何被嵌套的<beans>元素都会导致此方法的递归。为了正确的传播和保存<beans>的默认属性、
  14. // 保持当前(父)代理的跟踪,它可能为null
  15. // 为了能够回退,新的(子)代理具有父的引用,最终会重置this.delegate回到它的初始(父)引用。
  16. // 这个行为模拟了一堆代理,但实际上并不需要一个代理
  17. BeanDefinitionParserDelegate parent = this.delegate;
  18. //2.1创建一个新的代理,并初始化一些默认值
  19. this.delegate = createDelegate(getReaderContext(), root, parent);
  20. //默认名称空间是"http://www.springframework.org/schema/beans"
  21. if (this.delegate.isDefaultNamespace(root)) {
  22. String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
  23. //我的xml文件中没有设置"profile",所以跳过
  24. if (StringUtils.hasText(profileSpec)) {
  25. String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
  26. profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
  27. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
  28. if (logger.isInfoEnabled()) {
  29. logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
  30. "] not matching: " + getReaderContext().getResource());
  31. }
  32. return;
  33. }
  34. }
  35. }
  36. //xml预处理,子类没有重写里面就是空实现
  37. preProcessXml(root);
  38. //2.2生成BeanDefinition,并注册在工厂中
  39. parseBeanDefinitions(root, this.delegate);
  40. //xml后处理,子类没有重写里面就是空实现
  41. postProcessXml(root);
  42. this.delegate = parent;
  43. }

2.1 createDelegate

跟踪标记2.1的方法

此方法在DefaultBeanDefinitionDocumentReader类中

入参 getReaderContext() 方法返回的是先前创建的 XmlReaderContext 对象

  1. //2.1创建一个新的代理,并初始化一些默认值
  2. this.delegate = createDelegate(getReaderContext(), root, parent);
  3. protected BeanDefinitionParserDelegate createDelegate(
  4. XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
  5. //用来解析XML bean definition的有状态代理类,用来被主解析器和其他扩展使用
  6. BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
  7. //进入此方法
  8. delegate.initDefaults(root, parentDelegate);
  9. return delegate;
  10. }

进入BeanDefinitionParserDelegate类的initDefaults方法

  1. /**
  2. * Initialize the default lazy-init, autowire, dependency check settings,
  3. * init-method, destroy-method and merge settings. Support nested 'beans'
  4. * element use cases by falling back to the given parent in case the
  5. * defaults are not explicitly set locally.
  6. *
  7. * 初始化默认值 default :·······等
  8. * 通过使用 parent default,来解决嵌套的'beans'元素情况,以防 default 在局部设定不明确
  9. */
  10. public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
  11. //进入此方法
  12. populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
  13. //默认没做任何实现
  14. this.readerContext.fireDefaultsRegistered(this.defaults);
  15. }

populateDefaults方法跟踪

入参this.defaults有默认实现

  1. private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();

第二个入参:当第一次进入此方法时,parent为null。

进入方法

  1. /**
  2. * Populate the given DocumentDefaultsDefinition instance with the default lazy-init,
  3. * autowire, dependency check settings, init-method, destroy-method and merge settings.
  4. * Support nested 'beans' element use cases by falling back to <literal>parentDefaults</literal>
  5. * in case the defaults are not explicitly set locally.
  6. *
  7. * 用默认的值填充DocumentDefaultsDefinition实例
  8. * 通过使用parentDefaults(父代理的default属性),来解决嵌套的'beans'元素情况,以防默认值在局部设定不明确
  9. */
  10. protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
  11. //根元素上如果没有设定值,则返回"default"字符串
  12. String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
  13. //如果为"default",先看parentDefaults有没有,有用它的,没有用"false"
  14. if (DEFAULT_VALUE.equals(lazyInit)) {
  15. // Potentially inherited from outer <beans> sections, otherwise falling back to false.
  16. // 可能从外部<beans>继承,否则返回false
  17. lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
  18. }
  19. defaults.setLazyInit(lazyInit);
  20. String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
  21. if (DEFAULT_VALUE.equals(merge)) {
  22. // Potentially inherited from outer <beans> sections, otherwise falling back to false.
  23. merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
  24. }
  25. defaults.setMerge(merge);
  26. String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
  27. if (DEFAULT_VALUE.equals(autowire)) {
  28. // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
  29. autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
  30. }
  31. defaults.setAutowire(autowire);
  32. // Don't fall back to parentDefaults for dependency-check as it's no longer supported in
  33. // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it.
  34. // 依赖检查不会采用parentDefaults,因为在3.0之后已不再支持。因此,嵌套的<beans>不会使用parentDefaults
  35. defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
  36. if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
  37. defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
  38. }
  39. else if (parentDefaults != null) {
  40. defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
  41. }
  42. if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
  43. defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
  44. }
  45. else if (parentDefaults != null) {
  46. defaults.setInitMethod(parentDefaults.getInitMethod());
  47. }
  48. if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
  49. defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
  50. }
  51. else if (parentDefaults != null) {
  52. defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
  53. }
  54. //extractSource方法这里没有做任何实现,默认返回null
  55. defaults.setSource(this.readerContext.extractSource(root));
  56. }

2.2 parseBeanDefinitions

跟踪标记2.2的方法

在DefaultBeanDefinitionDocumentReader类中

  1. //2.2生成BeanDefinition,并注册在工厂中
  2. parseBeanDefinitions(root, this.delegate);
  3. /**
  4. * Parse the elements at the root level in the document:
  5. * "import", "alias", "bean".
  6. *
  7. * 解析在文档中根层级的元素:"import", "alias", "bean".
  8. */
  9. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
  10. //默认名称空间是"http://www.springframework.org/schema/beans"
  11. //进入条件
  12. if (delegate.isDefaultNamespace(root)) {
  13. //获取根元素下的子Node,注意,Node不一定是子标签,可能是回车,可能是注释
  14. NodeList nl = root.getChildNodes();
  15. for (int i = 0; i < nl.getLength(); i++) {
  16. Node node = nl.item(i);
  17. if (node instanceof Element) {
  18. //拿到了<beans>下的子标签
  19. Element ele = (Element) node;
  20. if (delegate.isDefaultNamespace(ele)) {
  21. //3.如果该标签属于beans的名称空间,则进入这个方法
  22. //xmlns="http://www.springframework.org/schema/beans"
  23. parseDefaultElement(ele, delegate);
  24. }
  25. else {
  26. //4.如果该标签属于其他的名称空间比如:context,aop等
  27. //xmlns:aop="http://www.springframework.org/schema/aop"
  28. //xmlns:context="http://www.springframework.org/schema/context"
  29. delegate.parseCustomElement(ele);
  30. }
  31. }
  32. }
  33. }
  34. else {
  35. delegate.parseCustomElement(root);
  36. }
  37. }

一个名称空间对应一个处理器。

比如在spring的配置文件applicatinoContext.xml中加入了这行代码:

  1. <!-- 启用注解 -->
  2. <context:annotation-config />

可以知道,标签annotation-config属于名称空间context。

那么context就对应着一个处理器。

解析的时候会先获取context对应的处理器。处理器中又会初始化一些解析器出来,一个解析器就对应着一个标签,像annotation-config就有对应自己的解析器。

不同的名称空间、不同的标签导致解析的方式非常的多,这里只拿两个常见的配置进行跟踪。

因为字数超过了限制,所以分成了三篇,点击下篇继续阅读

https://www.jianshu.com/p/46e27afd7d96

总结

  • 解析 Resource 对象,生成DOM文档对象
  • 2 注册BeanDefinitions

——————————————————————————————————

  • 2
  • 创建新的 delegate 对象,delegate 中有 defaults 属性,它是标签元素属性的一个集合。如果当前 Reader 对象中也有 delegate ,将其作为 parent 。取 parent 的 defaults ,作为未指定标签元素属性的情况下,新 defaults 的默认值。
  • 根据名称空间不同,分为beans默认名称空间的元素解析,和其他自定义元素解析。一般来说,一个名称空间对应一个处理器,处理器中又会初始化一些解析器出来。一个解析器就对应着一个标签,可以对不同的情况进行解析。

loadBeanDefinitions方法源码跟踪(一)的更多相关文章

  1. loadBeanDefinitions方法源码跟踪(三)

    因为字数超过了限制,所以分成了三篇,承接上篇: https://www.jianshu.com/p/46e27afd7d96 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 4.parseCus ...

  2. loadBeanDefinitions方法源码跟踪(二)

    因为字数超过了限制,所以分成了三篇,承接上篇: https://www.jianshu.com/p/a0cfaedf3fc5 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 3.parseDef ...

  3. obtainFreshBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  4. prepareRefresh方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  5. postProcessBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  6. prepareBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  7. erlang下lists模块sort(排序)方法源码解析(一)

    排序算法一直是各种语言最简单也是最复杂的算法,例如十大经典排序算法(动图演示)里面讲的那样 第一次看lists的sort方法的时候,蒙了,几百行的代码,我心想要这么复杂么(因为C语言的冒泡排序我记得不 ...

  8. Java源码跟踪阅读技巧

    转:https://www.jianshu.com/p/ab865109070c 本文基于Eclipse IDE 1.Quick Type Hierarchy 快速查看类继承体系. 快捷键:Ctrl ...

  9. Thread.interrupt()源码跟踪

    1 JDK源码跟踪 // java.lang.Thread public void interrupt() { if (this != Thread.currentThread()) checkAcc ...

随机推荐

  1. maven热部署

    1.启动tomcat 2.修改 tomat/conf/tomcat-users.xml   配置用户名.密码.角色       manager-gui:图形界面的权限(调试时配置)       man ...

  2. Python 基础之面向对象之异常处理

    一.认识异常 1.常用异常报错的错误类型 IndexError                索引超出序列的范围 KeyError                  字典中查找一个不存在的关键字 Na ...

  3. 并发编程之第三篇(synchronized)

    并发编程之第三篇(synchronized) 3. 自旋优化 4. 偏向锁 撤销-其它线程使用对象 撤销-调用wait/notify 批量重偏向 批量撤销 5. 锁消除 4.7 wait/notify ...

  4. Python - 工具

    Anaconda - 自带Conda,可以自定义环境 Pycharm zeal - API离线查看,类似于Dash

  5. oracle 高级函数

    原 oracle 高级函数 2017年08月17日 16:44:19 阅读数:1731 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u013278 ...

  6. 怎么修改Anaconda 中 jupyter notebook 文件的保存位置

    安装完 anaconda ,在jupyter notebook 中创建的文件的默认保存位置为C:\User\电脑名 修改保存位置 1.打开 anaconda prompt 2.输入 jupyter n ...

  7. c++11的记录

    decltype()类型指示符 设定一个返回值是int的函数f(),通过使用 decltype(f()) sum = x; 此时decltype()接受一个从f()返回的int型的值,并将sum设置为 ...

  8. Navigation源码(一) move_base最全解析

    一.概述 目测是全网最全的解析,花了几个小时通读并整理的,供大家参考学习. 概况的话可以看下古月居 https://www.guyuehome.com/270,其实它是翻译官方的,英语ok的可以去ro ...

  9. 110、Java中String类之字符串文本拆分

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  10. java对sql server的增删改查

    package Database; import java.sql.*; public class DBUtil { //这里可以设置数据库名称 private final static String ...