美文网首页
5. Bean配置元数据解析

5. Bean配置元数据解析

作者: wyh001 | 来源:发表于2023-09-23 14:25 被阅读0次

解析xml配置文件、java注解类、java配置类为BeanDefinition

一、解析xml配置文件

Xml配置读取器

  • BeanDefinitionReader
    • XmlBeanDefinitionReader
  1. 读取文件名称、Resource抽象,将其解析为Document

    • DocumentLoader 文档加载器
  2. 读取Document里的信息,将其解析BeanDefinition,并注册到IoC容器中

    • BeanDefinitionDocumentReader
xml解析.png
  1. 委派BeanDefinitionParserDelegate去解析xml元素和属性
    • 支持默认自定义命名空间
    • NamespaceHandlerResolver 命名空间解析器
      • DefaultNamespaceHandlerResolver 加载META-INF/spring.handlers文件中声明的命名空间处理器
    • NamespaceHandler命名空间处理器
BeanDefinitionParserDelegate.png
  • GenericBeanDefinition

  • NamespaceHandler 命名空间处理器

NamespaceHandler.png
  • 支持对自定义元素的解析

  • 增强默认元素功能,装饰器模式,通过解析自定义元素、属性的方式进行装饰

    (1)如下图p命名空间,即为装饰bean元素,解析器为:SimplePropertyNamespaceHandler

    命名空间解析器类声明在META-INF/spring.handlers文件内,可通过查找该文件定位解析器类

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean name="s5BeanDemo1" class="org.example.s5.S5BeanDemo1"
              p:attr1="a1"
              p:attr2="a2"/>
    </beans>
    

    (2)如下图aop:scoped-proxy元素,通过定义aop命名空间解析器对<bean>进行增强:AopNamespaceHandler

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean name="s5BeanDemo2" class="org.example.s5.S5BeanDemo2">
            <!-- 装饰 -->
            <aop:scoped-proxy proxy-target-class="true"/>
        </bean>
    </beans>
    

    解析<bean>元素源码如下:

    // DefaultBeanDefinitionDocumentReader#processBeanDefinition
    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));
        }
    }
    

二、扫描类路径

扫描类路径,通过过滤条件筛选出候选类

TypeFilter 过滤器接口

默认注解过滤器AnnotationTypeFilter支持的注解

  • @Component
  • @ManagedBean
  • @Named

ConditionEvaluator 候选条件评估器

  • @Conditional

ClassPathBeanDefinitionScanner 扫描器

  1. 扫描类路径下的文件

  2. 使用索引@Indexed获取候选类

  3. 处理通用注解

    • AnnotationConfigUtils#processCommonDefinitionAnnotations(AnnotatedBeanDefinition)
    • @Lazy
    • @Primary
    • @DependsOn
  4. 注册注解配置处理器

    • AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry)
    • ConfigurationClassPostProcessor处理@Configuration
  5. ScannedGenericBeanDefinition

示例

private static void s5_1() {
    final DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
    final ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(defaultListableBeanFactory);

    final int count = classPathBeanDefinitionScanner.scan("org.example.service.s5");
    log.info("加载数量【{}】", count);

    final String[] beanDefinitionNames = defaultListableBeanFactory.getBeanDefinitionNames();
    log.info("[{}]", Arrays.toString(beanDefinitionNames));
}

三、解析java配置类

AnnotatedBeanDefinitionReader

  • AnnotatedGenericBeanDefinition
  • 注册注解配置处理器
    • AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry)
    • ConfigurationClassPostProcessor处理@Configuration

四、解析@Configuration配置类

在前三种解析方式中,都可以支持解析配置类,这种方式是通过扩展IoC容器生命周期接口实现的

ConfigurationClassPostProcessor

  • 解析配置类
  • 条件装配
ConfigurationClassPostProcessor.png

步骤

  1. 读取IoC容器中所有注册的BeanDefinition

  2. 筛选出配置类的BeanDefinition,通过读取元数据,将其解析为ConfigurationClass列表

    • ConfigurationClassParser
  3. 读取ConfigurationClass中的信息,构建成BeanDefinition列表,注册到IoC容器中

    ConfigurationClassBeanDefinitionReader

解析流程

解析流程.png

读取流程

读取注册.png

建议

@Configuration类中定义@Bean方法创建BeanFactoryPostProcessor时,使用static限定符,避免配置类被过早地实例化

相关文章

网友评论

      本文标题:5. Bean配置元数据解析

      本文链接:https://www.haomeiwen.com/subject/yemxbdtx.html