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或容器中
- ClassPathXmlApplicationContext#getConfigResources() 方法中,通過 getConfigResources() 這個方法將 所有 xml 文件封裝成 Resource對象
- 循環 resource 對象,解析每個xml文件
- 進入 XmlBeanDefinitionReader 類中的 loadBeanDefinitions 方法進行xml 解析
spring 使用 dom4j 解析xml - 在 DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法中,通過 xml 的root根節點判斷是默認的標簽還是自定義的標簽,分別進行解析。
- 通過xml根節點獲取所有子節點,循環每個子節點,並判斷子節點是默認標簽還是自定義標分別進行解析。
- 將每個標簽的元素解析后封裝為 BeanDefinition 對象。 BeanDefinition 對象再封裝為 BeanDefinitionHolder 對象,BeanDefinitionHolder包含 bean的名字、別名和 bean的BeanDefinition對象.
- 進入 XmlBeanDefinitionReader 類中的 loadBeanDefinitions 方法進行xml 解析
默認標簽:import標簽、alias 標簽、bean 標簽 、beans 標簽
自定義標簽:spring mvc 自定義的標簽和自己擴展的標簽等
BeanDefinition 說明
- 我們會把xml里面的標簽元素比如:bean、componentScan、annotation-config 等標簽封裝成 beanDefinition 對象
- 我們會把 annotation比如:@Service、@Controller、@Component、@Resource 等注解封裝成 BeanDefinition
自定義標簽解析
- 命名空間 namespaceUri, 也就是 beans 標簽的 xmlns 、 xmlns:context、xmlns:aop、xmlns:tx 后面uri
- 當解析某個標簽時會 根據某個標簽獲取對應的命名空間uri,具體查看 BeanDefinitionParserDelegate#parseCustomElement(Element ele)方法
- 通過解析命名空間 uri,並實例化所對應的 命名空間處理類對象,這個解析過程會調用 命名空間處理類中的 init()方法,注冊所有關於這個命名空間 有關元素的所有解析器。具體查看 DefaultNamespaceHandlerResolver#resolve(String namespaceUri)方法
- 調用某個命名空間的處理器的 parse方法,例如:ContextNamespaceHandler 類是 xmlns:context 的命名空間處理類
查看 xmlns:context 的命名空間
- 進入 spring-context 模塊
- 進入 resources/META-INF/ 文件夾下面
- 查看 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解析類里面完成了
- 基本包的掃描
- 類型過濾器的配置
- annotation-config配置的兼容
- 注解處理器BeanPostProcessor的注冊
分析 AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
- AutowiredAnnotationBeanPostProcessor 類 就是 @Autowire 注解的支持
- RequiredAnnotationBeanPostProcessor 類 就是 @Required 注解的支持
- CommonAnnotationBeanPostProcessor 類就是對 jsr250的支持,也就是 @Resources
所有生成的beanDifinition對象都會注冊緩存到beanDefinitionMap中key就是beanName,value 就是beanDefinition , 然后會把beanName放到List里面去,beanDifinitionNames 就是這個list