前言: IOC的Bean从xml中进行解析到注册到IOC容器中, 之前只知道容器的加载流程,具体实现却一直模糊.今天正好追了源代码并记录下来



简单的注册代码

  1. // 获取资源
  2. ClassPathResource resource = new ClassPathResource("org/springframework/beans/factory/xml/test.xml"); // <1>
  3. // 获取 BeanFactory
  4. DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
  5. // 根据新建的 BeanFactory 创建一个 BeanDefinitionReader 对象,该 Reader 对象为资源的解析器
  6. XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
  7. // 装载资源
  8. reader.loadBeanDefinitions(resource);

这段代码包含了spring对加载、解析、处理、注册的全部流程


reader.loadBeanDefinitions()

前三段代码是一个获取资源输入流及准备的过程, 从装在资源的位置开始

  1. 方法点进来可以看到对resource又一次进行了包装,**EncodedResource**增加了编码格式, 可以防止乱码

image.png

  1. 这段方法就是一个验证然后调用下一层方法 ```java public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {

    1. Assert.notNull(encodedResource, "EncodedResource must not be null");
    2. if (logger.isTraceEnabled()) {
    3. logger.trace("Loading XML bean definitions from " + encodedResource);
    4. }
    5. // 获取已经加载过的资源
    6. Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    7. if (currentResources == null) {
    8. currentResources = new HashSet<>(4);
    9. this.resourcesCurrentlyBeingLoaded.set(currentResources);
    10. }
    11. if (!currentResources.add(encodedResource)) { // 将当前资源加入记录中。如果已存在,抛出异常
    12. throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    13. }
    14. try {
    15. // 从 EncodedResource 获取封装的 Resource ,并从 Resource 中获取其中的 InputStream
    16. InputStream inputStream = encodedResource.getResource().getInputStream();
    17. try {
    18. InputSource inputSource = new InputSource(inputStream);
    19. if (encodedResource.getEncoding() != null) { // 设置编码
    20. inputSource.setEncoding(encodedResource.getEncoding());
    21. }
    22. // 核心逻辑部分,执行加载 BeanDefinition
    23. ※※※※※※※※※※※
    24. return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    25. ※※※※※※※※※※※
    26. } finally {
    27. inputStream.close();
    28. }
    29. } catch (IOException ex) {
    30. throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex);
    31. } finally {
    32. // 从缓存中剔除该资源
    33. currentResources.remove(encodedResource);
    34. if (currentResources.isEmpty()) {
    35. this.resourcesCurrentlyBeingLoaded.remove();
    36. }
    37. }

    }

  1. 3. doLoadBeanDefinitions() 方法获取document,实例然后根据 Document 实例,注册 Bean 信息
  2. 3. registerBeanDefinitions() 创建XmlReaderContext 进行注册
  3. ```java
  4. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
  5. // 创建 BeanDefinitionDocumentReader 对象
  6. BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
  7. // 获取已注册的 BeanDefinition 数量
  8. int countBefore = getRegistry().getBeanDefinitionCount();
  9. // 创建 XmlReaderContext 对象
  10. // 注册 BeanDefinition
  11. documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
  12. // 计算新注册的 BeanDefinition 数量
  13. return getRegistry().getBeanDefinitionCount() - countBefore;
  14. }
  1. org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions

点了这么久终于到了真正重要的地方

  1. // 解析前处理
  2. preProcessXml(root);
  3. // 解析
  4. parseBeanDefinitions(root, this.delegate);
  5. // 解析后处理
  6. postProcessXml(root);
  1. parseBeanDefinitions(root, this.delegate)再次点进来
  1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  2. // 进行 bean 元素解析。
  3. // 如果解析成功,则返回 BeanDefinitionHolder 对象。而 BeanDefinitionHolder 为 name 和 alias 的 BeanDefinition 对象
  4. // 如果解析失败,则返回 null 。
  5. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
  6. if (bdHolder != null) {
  7. // 进行自定义标签处理
  8. bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
  9. try {
  10. // 进行 BeanDefinition 的注册
  11. // Register the final decorated instance.
  12. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
  13. } catch (BeanDefinitionStoreException ex) {
  14. getReaderContext().error("Failed to register bean definition with name '" +
  15. bdHolder.getBeanName() + "'", ele, ex);
  16. }
  17. // 发出响应事件,通知相关的监听器,已完成该 Bean 标签的解析。
  18. // Send registration event.
  19. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
  20. }
  21. }

beanName注册

BeanDefinitionReaderUtils.registerBeanDefinition();
最终会注册到
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

bean标签注册

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

总结

可以看到spring中使用了很多的设计模式, 有效的提高了代码的可维护性及可读性.在beanname注册时调用静态方法,而在bean标签注册时则使用监听器模式.