• 1-spring xml 和 注解 解析过程


    spring mvc 入口 DispatcherServlet,类关系图如下所示

    DispatcherServlet 就是一个 Servlet,那Servlet 的初始化方法 init()在哪里,通过类图可知,可以查看 HttpServletBean 中的 init() 方法,进行 Servlet初始化.

    xml解析和注解 解析入口

    经过一些xml和spring 初始化配置加载后,进入AbstractApplicationContext#refresh()方法

    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    

    进入 AbstractRefreshableApplicationContext#refreshBeanFactory()方法,通过 loadBeanDefinitions(beanFactory) 方法解析 xml 和注解

    • xml的解析类
      AbstractXmlApplicationContext
    • 注解的解析类
      AnnotationConfigWebApplicationContext

    xml 解析过程 类的流转

    • 将xml 或 properties 通过 ResourceLoader 加载为 Resource 对象,得到 Resource 对象就得到了文件所对应的 文件流,这个文件流在解析 xml 时会用到。
    • 每个 Resource 对象 都有对应的 Reader对象,Reader对象将配置封装成 BeanDefinition
    • BeanDefinition 在放入 map或容器中 

    1. ClassPathXmlApplicationContext#getConfigResources() 方法中,通过 getConfigResources() 这个方法将 所有 xml 文件封装成 Resource对象
    2. 循环 resource 对象,解析每个xml文件
      1. 进入 XmlBeanDefinitionReader 类中的 loadBeanDefinitions 方法进行xml 解析
        spring 使用 dom4j 解析xml
      2. 在 DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法中,通过 xml 的root根节点判断是默认的标签还是自定义的标签,分别进行解析。
      3. 通过xml根节点获取所有子节点,循环每个子节点,并判断子节点是默认标签还是自定义标分别进行解析。
      4. 将每个标签的元素解析后封装为 BeanDefinition 对象。 BeanDefinition 对象再封装为 BeanDefinitionHolder 对象,BeanDefinitionHolder包含 bean的名字、别名和 bean的BeanDefinition对象.

    默认标签:import标签、alias 标签、bean 标签 、beans 标签
    自定义标签:spring mvc 自定义的标签和自己扩展的标签等

    BeanDefinition 说明

    • 我们会把xml里面的标签元素比如:bean、componentScan、annotation-config 等标签封装成 beanDefinition 对象
    • 我们会把 annotation比如:@Service、@Controller、@Component、@Resource 等注解封装成 BeanDefinition

    自定义标签解析

    1. 命名空间 namespaceUri, 也就是 beans 标签的 xmlns 、 xmlns:context、xmlns:aop、xmlns:tx 后面uri
    2. 当解析某个标签时会 根据某个标签获取对应的命名空间uri,具体查看 BeanDefinitionParserDelegate#parseCustomElement(Element ele)方法
    3. 通过解析命名空间 uri,并实例化所对应的 命名空间处理类对象,这个解析过程会调用 命名空间处理类中的 init()方法,注册所有关于这个命名空间 有关元素的所有解析器。具体查看 DefaultNamespaceHandlerResolver#resolve(String namespaceUri)方法
    4. 调用某个命名空间的处理器的 parse方法,例如:ContextNamespaceHandler 类是 xmlns:context 的命名空间处理类

    查看 xmlns:context 的命名空间

    1. 进入 spring-context 模块
    2. 进入 resources/META-INF/ 文件夹下面
    3. 查看 spring.handlers 配置文件 可以看到每个命名空间的 uri 对应一个类。
      例如 xmlns:context 对应的 uri http://www.springframework.org/schema/context 对应 ContextNamespaceHandler 类 每一个命名空间都有对应的解析类 NamespaceHandler ,每一个 命名空间解析类中都有所对应的 命名空间的元素解析器.
    http://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
    

    context 命名空间 说明

    例如:<context:annotation-config />
    context找uri,beans标签中有content对应的uri。
    spring.handlers里面就有uri对应的处理类,实现NamespaceHandler接口,就会把这个命名空间对应的标签对应的处理注册进来。

    如果解析标签 component-scan 时,那么解析类就是 ComponentScanBeanDefinitionParser 类,并调用 component-scan 标签对应解析类的 parse 方法进行解析

    在ComponentScanBeanDefinitionParser解析类里面完成了

    1. 基本包的扫描
    2. 类型过滤器的配置
    3. annotation-config配置的兼容
    4. 注解处理器BeanPostProcessor的注册

    分析 AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);

    1. AutowiredAnnotationBeanPostProcessor 类 就是 @Autowire 注解的支持
    2. RequiredAnnotationBeanPostProcessor 类 就是 @Required 注解的支持
    3. CommonAnnotationBeanPostProcessor 类就是对 jsr250的支持,也就是 @Resources

    所有生成的beanDifinition对象都会注册缓存到beanDefinitionMap中key就是beanName,value 就是beanDefinition , 然后会把beanName放到List里面去,beanDifinitionNames 就是这个list

  • 相关阅读:
    函数指针的调用方式
    C++构造函数和析构函数顺序
    往android主项目中添加辅助项目
    Qt每次运行都是重新编译问题
    函数参数检验的研究
    动态链接库和静态链接库的区别(未完待续)
    MySQL 查看最大连接数, 当期连接数.
    Linux 命令
    Ext treelist 动态切换TreeStore
    Java 日期加减计算.
  • 原文地址:https://www.cnblogs.com/zhangjianbin/p/9085388.html
Copyright © 2020-2023  润新知