前言:
现时同学们对“net调用servlet接口”大概比较注重,朋友们都需要学习一些“net调用servlet接口”的相关知识。那么小编同时在网摘上网罗了一些对于“net调用servlet接口””的相关知识,希望咱们能喜欢,小伙伴们快快来了解一下吧!DispatcherServlet其实是Servlet接口的实现类,它的本质其实就是一个Servlet。
在讲DispatcherServlet之前,首先介绍一下Servlet的生命周期。
Servlet的生命周期
1. init : 初始化
当Servlet第一次被请求时,服务器就会调用init()方法初始化一个Servlet对象,但是这个方法在后续的请求中不会再次被调用,仅仅只会调用一次。在调用这个方法时,Servlet容器会传入一个ServletConfig对象来对Servlet对象进行初始化。
当发送http请求时:StandardWrapper类会调用allocate()方法给Servlet分配一个初始化的实例。
private synchronized void initServlet(Servlet servlet) throws ServletException { // 如果servlet已被初始化,则return if (instanceInitialized && !singleThreadModel) return; // Call the initialization method of this servlet try { if( Globals.IS_SECURITY_ENABLED) { boolean success = false; try { Object[] args = new Object[] { facade }; SecurityUtil.doAsPrivilege("init", servlet, classType, args); success = true; } finally { if (!success) { // destroy() will not be called, thus clear the reference now SecurityUtil.remove(servlet); } } } else { // 调用init()方法初始化,facade: 是ServletConfig的实现类 // 这一步会转到DispatcherServlet初始化的过程 servlet.init(facade); } instanceInitialized = true; } catch (UnavailableException f) { unavailable(f); throw f; } catch (ServletException f) { // If the servlet wanted to be unavailable it would have // said so, so do not call unavailable(null). throw f; } catch (Throwable f) { ExceptionUtils.handleThrowable(f); getServletContext().log(sm.getString("standardWrapper.initException", getName()), f); // If the servlet wanted to be unavailable it would have // said so, so do not call unavailable(null). throw new ServletException (sm.getString("standardWrapper.initException", getName()), f); } }
2. service
每次客户端请求这个Servlet时,Servlet容器就会调用service()方法处理请求;在后续的请求中,Servlet容器就只会调用这个方法了。
3. destroy
当服务器关闭或者停止时,Servlet容器就会调用destroy()销毁这个Servlet。
DispatcherServlet初始化
由于DispatcherServlet本质就是一个Servlet,它对Servlet进行了封装,它的生命周期与Servlet一致,当调用init(ServletConfig servletConfig)方法初始化的时候,这个时候采用Java面向对象思想:当子类继承父类时,如果子类没有重写父类的方法,则首先调用父类的方法,它的父类给他做了很多初始化的工作。
由于DispatcherServlet没有重写init(ServletConfig servletConfig)方法,它会找到父类的init(ServletConfig servletConfig)方法,然后调用。
1. 在其父类GenericServlet类中重写了init(ServletConfig servletConfig)方法
2. 从第一步可以看出DispatcherServlet对象会调用init()初始化方法,由于DispatcherServlet类没有重写init()方法,它会调用父类的init()方法,观察继承结构可知,只有HttpServletBean类重写了init()方法
@Override public final void init() throws ServletException { // ServletConfigPropertyValues 是静态内部类,使用 ServletConfig 获取 web.xml 中配置的参数 PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); if (!pvs.isEmpty()) { try { // 使用 BeanWrapper 来构造 DispatcherServlet 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) { if (logger.isErrorEnabled()) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); } throw ex; } } // 让子类实现的方法,这种在父类定义在子类实现的方式叫做模版方法模式 initServletBean(); }
3. 从上一步看到,它还要调用initServletBean方法,这个方法在DispatcherServlet类也没有重写,那只能往DispatcherServlet类的父类,HttpServletBean的子类找了,显而易见,只有FrameworkServlet类满足条件
initServletBean():建立 WebApplicationContext 容器(有时也称上下文),并加载 SpringMVC 配置文件中定义的 Bean 到该容器中,最后将该容器添加到 ServletContext 中。
protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; if (this.webApplicationContext != null) { // context实例在构造函数中被注入 wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { if (cwac.getParent() == null) { // 将 Spring 的容器设为 SpringMVC 容器的父容器 cwac.setParent(rootContext); } //刷新上下文环境 configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { // 如果 WebApplicationContext 为空,则进行查找,能找到说明上下文已经在别处初始化。 wac = findWebApplicationContext(); } if (wac == null) { // 如果servlet仍没有context实例,则以 Spring 的容器为父上下文建立一个新的。 wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { // Either the context is not a ConfigurableApplicationContext with refresh // support or the context injected at construction time had already been // refreshed -> trigger initial onRefresh manually here. synchronized (this.onRefreshMonitor) { // 模版方法,由其子类DispatcherServlet 实现 onRefresh(wac); } } if (this.publishContext) { // 发布这个 WebApplicationContext 容器到 ServletContext 中 String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); } return wac; }
4. 终于,回到我们的子类DispatcherServlet中执行onRefresh(ApplicationContext context)方法中刷新上下文
@Overrideprotected void onRefresh(ApplicationContext context) { initStrategies(context);}/** * Initialize the strategy objects that this servlet uses. * <p>May be overridden in subclasses in order to initialize further strategy objects. */protected void initStrategies(ApplicationContext context) { //初始化上传文件解析器(或者是多部分请求解析器) initMultipartResolver(context); //初始化本地化解析器 initLocaleResolver(context); //初始化主题解析器 initThemeResolver(context); //初始化处理器映射器HandlerMapping --重点 initHandlerMappings(context); //初始化处理器适配器 initHandlerAdapters(context); //初始化处理器异常解析器 initHandlerExceptionResolvers(context); //初始化请求到视图名翻译器 initRequestToViewNameTranslator(context); //初始化视图解析器 initViewResolvers(context); //初始化重定向数据管理器 initFlashMapManager(context);}
下面对处理器映射器HandlerMapping类初始化进行一个说明:
initHandlerMappings() 方法从 SpringMVC 的容器及 Spring 的容器中查找所有的 HandlerMapping 实例,并把它们放入到 handlerMappings 这个 list集合 中。这个方法并不是对 HandlerMapping 实例的创建,HandlerMapping 实例是在上面 WebApplicationContext 容器初始化,即 SpringMVC 容器初始化的时候创建的。
private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { //从SpringMVC的IOC容器及Spring的IOC容器中查找HandlerMapping实例 Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); // 按照一定排序规则放入list中 AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // 如果没有,则加载默认的 if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isTraceEnabled()) { logger.trace("No HandlerMappings declared for servlet '" + getServletName() + "': using default strategies from DispatcherServlet.properties"); } }}
到此,DispatcherServlet就初始化完成了。
然后,调用service方法开始处理http请求。
下面,主要讲DispatcherServelt如何处理请求,并封装结果响应。
DispatcherServelt处理请求
在分析处理请求之前,先看一下总体流程:
下面是更加详细的版本
1. HttpServlet类处理service
同样的分析,由于service(ServletResquest, ServletResponse)方法其父类HttpServlet已经重写好了,子类没有重写,则调用父类的service()方法。
@Overridepublic 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; // 调用子类FrameworkServlet判断请求是否是Patch请求或者null, 如果是的话交给子类处理 // 如果不是返回自己处理 service(request, response);}
2. FrameworkServlet类处理service
@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (httpMethod == HttpMethod.PATCH || httpMethod == null) { processRequest(request, response); } else { // 返回给HttpServlet类处理 super.service(request, response); } }
3 HttpServlet类继续处理service方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取请求方法名称 String method = req.getMethod(); // 判断请求方法类型,进入到对应的处理分支 // Get请求 if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else { long ifModifiedSince; try { ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) { // Invalid date header - proceed as if none was set ifModifiedSince = -1; } if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } // Head请求 } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); // Post } else if (method.equals(METHOD_POST)) { doPost(req, resp); // Put } else if (method.equals(METHOD_PUT)) { doPut(req, resp); // Delete } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); // Options } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); // Trace } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // 什么请求都不匹配,返回error String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); }}
4. 以Get请求为例,下面调用doGet请求,由于HttpServlet的子类FrameworkServlet类重写了HttpServlet的doGet方法,因此,将调用FrameworkServlet类的doGet请求。
@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response);}protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); initContextHolders(request, localeContext, requestAttributes); try { // 终于,在这一步,子类DispatcherServlet重写了doService方法 doService(request, response); } catch (ServletException | IOException ex) { failureCause = ex; throw ex; } catch (Throwable ex) { failureCause = ex; throw new NestedServletException("Request processing failed", ex); } finally { resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } logResult(request, response, failureCause, asyncManager); publishRequestHandledEvent(request, response, startTime, failureCause); } }
5. 千呼万唤,终于进入到DispatcherServlet类的doService()方法中
在doService方法中,主要是对请求做一些赋值,然后重中之重调用doDispatch方法处理请求。
@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request); // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); if (this.flashMapManager != null) { FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); } RequestPath previousRequestPath = null; if (this.parseRequestPath) { previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE); ServletRequestPathUtils.parseAndCache(request); } try { // 终于要处理request啦 doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request); }}
6. DispatcherServlet的doDispatch处理请求和返回响应
doDispatch处理的大致流程:
通过HandlerMapping获取请求对应的Handler再通过Handler找到对应的HandlerAdapterHandlerAdapterd调用handler方法得到ModelAndView(连接“业务逻辑层”与“视图展示层”的桥梁)通过ModelAndView 获得 View,再通过它的 Model 对 View 进行渲染
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { //1. 判断是否是文件上传请求 processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // 2. 遍历所有的 HandlerMapping 找到与请求对应的 Handler,并将其与一堆拦截器封装到 HandlerExecutionChain 对象中。 // 返回的HandlerExecutionChain请求处理器链对象封装了handler和interceptors. mappedHandler = getHandler(processedRequest); // 如果没有对应的handler,返回404 if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 3. 获取处理请求的处理器适配器HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 处理 last-modified 请求头 String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 请求方法前置拦截,如果返回true 表示会执行到目标方法(请求方法) 如果返回false的情况下,直接return。 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 5. 这一步就是调用对应的controller控制器,并返回结果视图对象 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 如果是异步模式,则返回 if (asyncManager.isConcurrentHandlingStarted()) { return; } // 6. 如果mv不为null,则给其ViewName设置初始默认值 applyDefaultViewName(processedRequest, mv); // 7. 后置拦截器的postHandle方法的处理 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } // 8. 处理返回结果;(异常处理、页面渲染、拦截器的afterCompletion触发等) processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { //判断是否执行异步请求 if (mappedHandler != null) { // 如果是的话,就替代拦截器的postHandle 和 afterCompletion方法执行 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // 删除上传请求的资源 if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }}
标签: #net调用servlet接口