前言
spring web 主要是要是通过 DispatcherServlet 来对请求进行分发,现在来看看他注册到 web 容器中的过程。
版本号
spring-boot:2.3.5
注册DispatcherServlet
在servlet 3的环境下,可以使用代码进行注册,与配置在 web.xml 中一样。主要查看在spring boot 下如何 将 DispatcherServlet 添加进ServletContext 中的代码。
spring 提供了 ServletContextInitializer
来支持操作 ServletContext
,以达到注册 Servlet、过滤器、监听器、初始参数设置等操作。
@FunctionalInterface
public interface ServletContextInitializer {
/**
* 使用初始化所需的所有Servlet,过滤器,监听器上下文参数和属性来配置给定的ServletContext。
*/
void onStartup(ServletContext servletContext) throws ServletException;
}
ServletContextInitializer
的实现类 ServletRegistrationBean
提供了注册 Servlet
的能力,而DispatcherServletRegistrationBean
实现了 ServletRegistrationBean
来注册 DispatcherServlet
。
//
public class ServletRegistrationBean<T extends Servlet> extends DynamicRegistrationBean<ServletRegistration.Dynamic> {
@Override
protected ServletRegistration.Dynamic addRegistration(String description,
ServletContext servletContext) {
String name = getServletName();
return servletContext.addServlet(name, this.servlet);
}
}
// 注册DispatcherServlet
public class DispatcherServletRegistrationBean extends ServletRegistrationBean<DispatcherServlet>
implements DispatcherServletPath {
public DispatcherServletRegistrationBean(DispatcherServlet servlet, String path) {
super(servlet);
Assert.notNull(path, "Path must not be null");
this.path = path;
super.addUrlMappings(getServletUrlMapping());
}
}
执行 ServletContextInitializer
的流程
spring boot中,启动程序准备好环境后将会进入刷新,在刷新流程中将会根据配置创建对应的web容器,如Tomcat、Jetty等,以创建tomcat 为例,在创建WebServer 中,判断使用的外部容器还是 springboot 提供的容器。
- 如果使用的事外部容器,则通过 BeanFactory 获取 ServletContextInitializer 实现类,并调用他的 onStartup 方法。
- 如果使用的是SpringBoot提供的tomcat容器,会去创建 tomcat,在创建后将启动 tomcat,执行 ServletContextInitializer的 onStartup 方法。
//AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
onRefresh(); // 初始化其他特殊的bean
}
//ServletWebServerApplicationContext
public class ServletWebServerApplicationContext extends GenericWebApplicationContext
implements ConfigurableWebServerApplicationContext {
@Override
protected void onRefresh() {
super.onRefresh();
try {
// 这里是关键点,也就是创建webServer。
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
// 获取当前WebServer
WebServer webServer = this.webServer;
// 获取Servlet上下文,如果使用外部 tomcat,则在第一次执行这个方法时,通过 SpringServletContainerInitializer 将ServletContext 传递进来,否则在创建webServer的时候进行创建。
ServletContext servletContext = getServletContext();
// 都为空,则说明还没有创建Web服务与 servlet 容器
if (webServer == null && servletContext == null) {
// 获取构造工厂
ServletWebServerFactory factory = getWebServerFactory();
//获取所有ServletContextInitializer类型的bean,以备webServer服务创建好之后调用
this.webServer = factory.getWebServer(getSelfInitializer());
// 注册web服务关闭时的处理器,进行收尾操作
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
}
// 使用外部tomcat会进入,调用 ServletContextInitializer
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
}
获取 ServletContextInitializer
的代码
// 返回匿名类,在匿名类中调用 selfInitialize 方法
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
return this::selfInitialize;
}
// 在该方法中进行具体的注册操作
private void selfInitialize(ServletContext servletContext) throws ServletException {
// 。。。略
// 主要关注这里,getServletContextInitializerBeans(),获取所有的ServletContextInitializerBean
// 然后调用所有的 ServletContextInitializer#onStartup 方法向servletContext 中进行注册操作。
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
// 获取 ServletContextInitializer 实现类
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
return new ServletContextInitializerBeans(getBeanFactory());
}
// 自定义集合
public class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer>{
@SafeVarargs
public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
Class<? extends ServletContextInitializer>... initializerTypes) {
this.initializers = new LinkedMultiValueMap<>();
// 获取类型,默认使用 ServletContextInitializer
this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes)
: Collections.singletonList(ServletContextInitializer.class);
// 获取所有的 ServletContextInitializer ,并进行分类
addServletContextInitializerBeans(beanFactory);
// 排序
List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
.flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
.collect(Collectors.toList());
this.sortedList = Collections.unmodifiableList(sortedInitializers);
// 打印日志
logMappings(this.initializers);
}
// 获取所有的 ServletContextInitializer ,并进行分类
private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
for (Entry<String, ? extends ServletContextInitializer> initializerBean :
// 获取所有的 ServletContextInitializer 实现类 bean
getOrderedBeansOfType(beanFactory,initializerType)) {
addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);
}
}
}
// 根据不同的类型进去区分 Servlet\Filter\EventListener\ServletContextInitializer,并添加进 initializers 中
private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer,
ListableBeanFactory beanFactory) {
// servlet
if (initializer instanceof ServletRegistrationBean) {
Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet();
addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source);
}
// filter
else if (initializer instanceof FilterRegistrationBean) {
Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
}
// Filter
else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
}
// EventListener
else if (initializer instanceof ServletListenerRegistrationBean) {
EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener();
addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source);
}
// ServletContextInitializer
else {
addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory,
initializer);
}
}
/**
*
*/
private void addServletContextInitializerBean(Class<?> type, String beanName,
ServletContextInitializer initializer,
ListableBeanFactory beanFactory, Object source) {
this.initializers.add(type, initializer);
if (source != null) {
// Mark the underlying source as seen in case it wraps an existing bean
this.seen.add(source);
}
}
}
创建 WebServer
的代码( TomcatServletWebServerFactory
),并且调用 ServletContextInitializer#onStrat()
。
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
// 创建tomcat服务
Tomcat tomcat = new Tomcat();
// 。。。。略
// 准备上下文
prepareContext(tomcat.getHost(), initializers);
// 创建并启动,在启动时将调用 ServletContextInitializer#onStrat() 方法
return getTomcatWebServer(tomcat);
}
// 准备上下文
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
// 创建 TomcatContext,虽然不是 ServletContext 类,但是可以转换成ServletContext
TomcatEmbeddedContext context = new TomcatEmbeddedContext();
if (documentRoot != null) {
context.setResources(new LoaderHidingResourceRoot(context));
}
// 。。。。略
// 合并
ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
// 关联上下文
host.addChild(context);
// 配置上下文
configureContext(context, initializersToUse);
}
protected void configureContext(Context context, ServletContextInitializer[] initializers) {
// 创建tomcat启动器
TomcatStarter starter = new TomcatStarter(initializers);
if (context instanceof TomcatEmbeddedContext) {
TomcatEmbeddedContext embeddedContext = (TomcatEmbeddedContext) context;
// 设置启动回调
embeddedContext.setStarter(starter);
embeddedContext.setFailCtxIfServletStartFails(true);
}
// 将 TomcatStart 与上下文关联,添加 ContainerInitializer
// 然后由他来执行 ServletContextInitializer#onStartup
context.addServletContainerInitializer(starter, NO_CLASSES);
}
// 创建 TomcatWebServer
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}
public class TomcatWebServer implements WebServer{
// 构造器
public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
initialize();
}
// 初始化:启动 tomcat
private void initialize() throws WebServerException {
// 。。。。略
// Start the server to trigger initialization listeners
this.tomcat.start();
}
}