Servlet是一套Web应用的开发规范,我们按照这套规范编码就可以实现一个Web应用,使其在Web容器中运行。
我们最开始学习J2EE时,学习和创建的就是Servlet的实现类,后来学习了MVC框架以后,尤其是SpringMVC,就很少直接创建Servlet的实现类了。虽然SpringMVC简化和隐藏了Servlet,但是我们也要了解Servlet的运行原理,这样对了解SpringMVC的原理也很有帮助
首先看一下Servlet的类结构
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
Servlet是个接口,定义了init、service、destroy等方法。其中init方法在容器启动时(或Servlet第一次调用时)会被调用,进行Servlet的初始化工作;service方法会在容器接收到请求后处理请求时调用。
下面看一下Servlet接口的各个实现类,从而分析Servlet的初始化原理和Spring的DispatchServlet是如何作为请求分发器的。
GenericServlet:
/**重写init(ServletConfig)方法,将参数config保存在对象中,将init()方法交给实现类重写,这样既可以让本类的init(ServletConfig)得到执行,也可以让实现类的init()得到执行。这种方式在Servlet的实现类中经常用到:模板方法**/
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
重写了init方法,保存了配置参数的对象,将具体的init操作交给实现类
HttpServletBean:
@Override
public final void init() throws ServletException {
//注意看log的内容,是我们在启动tomcat时控制台经常看到的输出内容
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
try {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
}
/*很重要的方法,在本类中是空方法。HttpServletBean的init()方法做了基本的参数处理后,将其他的
init操作交给了实现类,实现类不重写init()方法,而是重写initServletBean(),这样它们都会得到执行。*/
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
FrameworkServlet:
//注意看log的内容,是我们在启动tomcat时控制台经常看到的输出内容
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
//初始化应用上下文
this.webApplicationContext = initWebApplicationContext();
//交给实现类继续做初始化工作,目前未见相关实现类重写了该方法
initFrameworkServlet();
}。。。
if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +elapsedTime + " ms");
}
}
/**
初始化应用上下文,包括子容器上下文和父容器上下文,onRefresh(ApplicationContext)方法交给实现类
处理,DispatchServlet会在此方法中对mvc-servlet.xml文件进行读取和参数配置初始化等工作
**/
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
//设置子容器的父容器
cwac.setParent(rootContext);
}
//初始化应用上下文对象
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (!this.refreshEventReceived) {
//实现类进行操作
onRefresh(wac);
}
。。。。。
return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
。。。。。。。//wac的初始化工作
//很重要的一步
wac.refresh();
}
//AbstractApplicationContext的方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
。。。。。//BeanFactory和MessageSource初始化
onRefresh();
。。。。。//注册监听器
}
}
}
DispatchServlet:
//调用DispatchServlet的onRefresh(ApplicationContext)方法,读取mvc-servlet.xml文件,并初始化
//HandlerMapping、HandlerAdapters等属性
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
HttpServlet:
//重写Servlet的service(ServletRequest,ServletResponse)方法,主要做了请求参数类型判断和参数转换
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
if (!(req instanceof HttpServletRequest &&
res instanceof HttpServletResponse)) {
throw new ServletException("non-HTTP request or response");
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);
}
//将请求分为POST、GET、DELETE等几种常见方法,然后分别进行处理。以前写Servlet时都是继承该类,然后
//重写doGet、doPost等方法,对请求进行处理。SpringMVC的处理方式于此不同。
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
。。。
doGet(req, resp);
。。。
}
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
}
。。。
}
FrameworkServlet:
/*重写service方法,增加了PATCH方法的处理,其他方法如GET会调用父类的FrameworkServlet重写了
doXxx方法,实际上会调用本类的doXxx方法,也就是调用SpringMVC的统一请求处理方法---p
rocessRequest(HttpServletRequest, HttpServletResponse)*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
。。。
try {
//具体的doService实现交给了子类
doService(request, response);
}
。。
publishRequestHandledEvent(request, response, startTime, failureCause);
。。。
}
DispatchServlet:
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
。。。//设置相关属性
try {//该方法是SpringMVC处理请求的关键,也是DispatchServlet分发请求的关键:根据
//pathHandlerMapping查询对应的HandlerExecutionChain,调用HandlerAdapter的handle方法进行处理,
//获取ModelAndView对象,最后处理结果。
doDispatch(request, response);
}
。。。//存储相关属性
}