在研究DispatchServlet之前必须先要知道DispatchServlet是在何时被注入到servletContext中的。
在上一篇中讲过,启动Tomcat服务是通过TomcatServletWebServerFactory类中的getWebServer方法来实现的,而getWebServer的参数是通过ServletWebServerApplicationContext类中的getSelfInitializer方法来实现的,下面是getSelfInitializer的源码:
private ServletContextInitializer getSelfInitializer() {
return this::selfInitialize;
}
通过查看类图可以得知ServletContextInitializer类是一个继承了函数式接口的类
再来看selfInitialize函数的源码
private void selfInitialize(ServletContext servletContext) throws ServletException {
this.prepareWebApplicationContext(servletContext);
this.registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(this.getBeanFactory(), servletContext);
Iterator var2 = this.getServletContextInitializerBeans().iterator();
while(var2.hasNext()) {
ServletContextInitializer beans = (ServletContextInitializer)var2.next();
// 主要方法
beans.onStartup(servletContext);
}
}
在运行的时候,将端点打在beans.onStartup()这个方法上时,发现beans是一些Filters和一些对应的RegistionBean,这些都是用于对请求进行处理的对象,其中就包括一个DispatchServletRegistionBean对象,该对象是用于将DispatchServlet对象注入到servletContext上下文中。
通过查看类图得知DispatchServletRegistionBean类为RegistrationBean的子类
DispatchServletRegistionBean类中没有onStartup方法,实际上执行的还是RegistrationBean类中的onStartup方法。RegistrationBean类中的onStartup方法源码如下所示
public final void onStartup(ServletContext servletContext) throws ServletException {
String description = this.getDescription();
if (!this.isEnabled()) {
logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
} else {
this.register(description, servletContext);
}
}
其中getDescription方法的源码很简单,就是获取一个字符串对象,最终调用的是ServletRegistrationBean类中的getDescription方法,源码如下
protected String getDescription() {
Assert.notNull(this.servlet, "Servlet must not be null");
return "servlet " + this.getServletName();
}
主要的注入方法为下面的redister方法,DispatchServletRegistionBean类中没有redister方法,实际上执行的是DynamicRegistrationBean类中的redister方法,源码如下
protected final void register(String description, ServletContext servletContext) {
D registration = this.addRegistration(description, servletContext);
if (registration == null) {
logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
} else {
this.configure(registration);
}
}
然后进入ServletRegistrationBean的addRegistration函数
protected Dynamic addRegistration(String description, ServletContext servletContext) {
String name = this.getServletName();
return servletContext.addServlet(name, this.servlet);
}
从这个函数中可以看出,前面的DispatchServletRegistionBean对象已经被加入到servletContext的上下。从DispatchServletRegistionBean的构造函数可以看出,DispatchServletRegistionBean的构造函数需要传入一个DispatchServlet对象,而这个DispatchServlet对象在DispatchServletRegistionBean的父类ServletRegistrationBean中作为一个成员变量,因此DispatchServletRegistionBean注入到servletContext也代表着DispatchServlet的注入成功。
public DispatcherServletRegistrationBean(DispatcherServlet servlet, String path) {
super(servlet, new String[0]);
Assert.notNull(path, "Path must not be null");
this.path = path;
super.addUrlMappings(new String[]{this.getServletUrlMapping()});
}
下一节再来看一看DispatchServlet类的源码,了解DispatchServlet是如何运作的。