概述
查看Spring源码发现有如下东西:
ServletContainerInitializer接口
首先我们要知道这是个Java EE规范中的接口,由具体的Servlet容器来实现,在Web容器启动时被回调。
作用
类似于一个监听容器启动的监听器。
用法
在实现该接口后,需要在SPI文件中注册,在Servlet容器启动时通过SPI从classpath下查找其实现类,实例化后进行回调。
举例
Spring的实现类
那实现类上标注了@HandlesTypes注解又是干嘛的呢?
@HandlesTypes注解
含义
这也是Java EE规范中的注解,表示当前ServletContainerInitializer的实现类,能处理的类型。这两个都是Servlet3.0中的东西。
主要作用
Servlet容器(例如tomcat)启动时,会将SPI注册的Java EE接口ServletContainerInitializer的所有的实现类(例如,SpringServletContainerInitializer)挨个回调其onStartup方法。
而onStartup方法是需要参数的,这时@HandlesTypes就派上用场了。
onStartup方法所需要的参数就通过@HandlesTypes注解传入。
实现原理
@HandlesTypes注解由Servlet容器提供支持(实现),参数中指定的所有实现类,利用字节码扫描框架(例如ASM、BCEL)从classpath中扫描出来,放入集合,传给回调方法onStartup的第一个参数。
言归正传,为什么Spring需要用到这部分注解?
我们总是能在传统的Spring项目看到如下Web容器配置文件。
为什么Spring项目中没有web配置文件?
通过创建Web初始化类,继承自AbstractAnnotationConfigDispatcherServletInitializer
去除web.xml配置文件的实现原理就得依靠Java EE提供的@HandlesTypes与ServletContainerInitializer了。
因此,Spring中使用该注解和接口的原因之一就是去除配置文件。
Spring去除配置文件的实现原理
有请看@HandlesTypes中参数WebApplicationInitializer的某个Spring-webmvc中的实现类:AbstractDispatcherServletInitializer。
注意:如果是SpringBoot项目这里就是唯一容器上下文。如果项目是SpringMVC+Spring,这里创建的上下文是Spring容器的子上下文,组成父子上下文。父子上下文特点是子容器(controller层)可访问父容器(service层,dao层)里的Bean,父容器不能访问子容器里的Bean,优点是层次分明。像是这种父子结构的容器,在@Service层是不能注入@Controller Bean的,原因如上。
因此我们得出结论,spring是通过代码中配置从而去除的web配置文件。
启动流程
假设Servlet容器是tomcat。
- 由tomcat在启动时根据SPI机制的ServiceLoader#load方法拿到所有JavaEE接口(ServletContainerInitializer)注册的实现类。
- Spring对该接口的实现类是SpringServletContainerInitializer,其类上标注了@HandlesTypes({WebApplicationInitializer.class})。
- tomcat从classpath下找到所有的WebApplicationInitializer实现类,将所有的实现类传入SpringServletContainerInitializer#onStartup方法的第一个参数,调用方法。
- 回到SpringServletContainerInitializer#onStartup方法中的逻辑,将所有的WebApplicationInitializer实现类的onStartup方法一一调用。
- WebApplicationInitializer的实现类之一是AbstractDispatcherServletInitializer,会创建spring容器、配置web.xml、注册过滤器。
当存在多个WebApplicationContext会设置其层级关系。
编写代码测试
理论与实践相结合,利用tomcat + @HandlesTypes与ServletContainerInitializer + Spring-webmvc模拟SpringBoot去除web.xml启动。
代码地址:https://github.com/lmmarisej/light-springboot。
最后
以上就是义气缘分为你收集整理的web容器启动Spring应用程序原理,@HandlesTypes与ServletContainerInitializer的全部内容,希望文章能够帮你解决web容器启动Spring应用程序原理,@HandlesTypes与ServletContainerInitializer所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复