wordpress灯箱插件,昆明做网站优化哪家好,没有备案的网站能否帮网上支付,电子商务网站建设描述一.DispatcherServlet 源码分析
本文仅了解源码内容即可。 1.观察我们的服务启动⽇志: 当Tomcat启动之后, 有⼀个核⼼的类DispatcherServlet, 它来控制程序的执⾏顺序.所有请求都会先进到DispatcherServlet#xff0c;执⾏doDispatch 调度⽅法. 如果有拦截器, 会先执⾏拦截器…一.DispatcherServlet 源码分析
本文仅了解源码内容即可。 1.观察我们的服务启动⽇志: 当Tomcat启动之后, 有⼀个核⼼的类DispatcherServlet, 它来控制程序的执⾏顺序.所有请求都会先进到DispatcherServlet执⾏doDispatch 调度⽅法. 如果有拦截器, 会先执⾏拦截器 preHandle() ⽅法的代码, 如果 preHandle() 返回true, 继续访问controller中的⽅法. controller当中的⽅法执⾏完毕后再回过来执⾏ postHandle() 和 afterCompletion() 返回给DispatcherServlet, 最终给浏览器响应数据. 1.1初始化(了解) DispatcherServlet的初始化⽅法 init() 在其⽗类 HttpServletBean 中实现的 主要作⽤是加载 web.xml 中 DispatcherServlet 的 配置, 并调⽤⼦类的初始化 web.xml是web项⽬的配置⽂件⼀般的web⼯程都会⽤到web.xml来ListenerFilterServlet等, Spring框架从3.1版本开始⽀持Servlet3.0, DispatcherServlet, 实现不再使⽤web.xml init() 具体代码如下 Overridepublic final void init() throws ServletException {try {// ServletConfigPropertyValues 是静态内部类使⽤ ServletConfig 获取web.xml 中配置的参数PropertyValues pvs newServletConfigPropertyValues(getServletConfig(), this.requiredProperties);// 使⽤ BeanWrapper 来构造 DispatcherServletBeanWrapper bw PropertyAccessorFactory.forBeanPropertyAccess(this);ResourceLoader resourceLoader newServletContextResourceLoader(getServletContext());bw.registerCustomEditor(Resource.class, newResourceEditor(resourceLoader, getEnvironment()));initBeanWrapper(bw);bw.setPropertyValues(pvs, true);} catch (BeansException ex) {}// 让⼦类实现的⽅法这种在⽗类定义在⼦类实现的⽅式叫做模版⽅法模式initServletBean();} 在 HttpServletBean 的 init() 中调⽤了 initServletBean() , 它是在 FrameworkServlet 类中实现的, 主要作⽤是建⽴ WebApplicationContext 容器(有时也称上下⽂), 并加载 SpringMVC 配置⽂件中定义的 Bean到该容器中, 最后将该容器添加到 ServletContext 中 initServletBean() 的具体代码 /*** Overridden method of {link HttpServletBean}, invoked after any bean properties* have been set. Creates this servlets WebApplicationContext.*/Overrideprotected final void initServletBean() throws ServletException {getServletContext().log(Initializing Spring getClass().getSimpleName() getServletName() );if (logger.isInfoEnabled()) {logger.info(Initializing Servlet getServletName() );}long startTime System.currentTimeMillis();try {//创建ApplicationContext容器this.webApplicationContext initWebApplicationContext();initFrameworkServlet();}catch (ServletException | RuntimeException ex) {logger.error(Context initialization failed, ex);throw ex;}if (logger.isDebugEnabled()) {String value this.enableLoggingRequestDetails ?shown which may lead to unsafe logging of potentially sensitive data :masked to prevent unsafe logging of potentially sensitive data;logger.debug(enableLoggingRequestDetails this.enableLoggingRequestDetails : request parameters and headers will be value);}if (logger.isInfoEnabled()) {logger.info(Completed initialization in (System.currentTimeMillis()- startTime) ms);}} 此处打印的⽇志, 也正是控制台打印出来的⽇志: 源码跟踪技巧 在阅读框架源码的时候, ⼀定要抓住关键点, 找到核⼼流程. 切忌从头到尾⼀⾏⼀⾏代码去看, ⼀个⽅法的去研究, ⼀定要找到关键流程, 抓住关键点, 先在宏观上对整个流程或者整个原理有⼀个认识, 有精⼒再去研究其中的细节 初始化web容器的过程中, 会通过onRefresh 来初始化SpringMVC的容器 protected WebApplicationContext initWebApplicationContext() {//...if (!this.refreshEventReceived) {//初始化Spring MVCsynchronized (this.onRefreshMonitor) {onRefresh(wac);}}return wac;}Overrideprotected void onRefresh(ApplicationContext context) {initStrategies(context);}/*** Initialize the strategy objects that this servlet uses.* pMay be overridden in subclasses in order to initialize further strategy objects.*/protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context)initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);
} 在initStrategies()中进⾏9⼤组件的初始化, 如果没有配置相应的组件就使⽤默认定义的组件(在 DispatcherServlet.properties中有配置默认的策略, ⼤致了解即可) ⽅法initMultipartResolver、initLocaleResolver、init、initRequestToViewNameTranslator、initFlashMapManager的处理⽅式⼏乎都⼀样(1.2.3.7.8,9),从应⽤⽂中取出指定的Bean, 如果没有, 就使⽤默认的. ⽅法initHandlerMappings、initHandlerAdapters、initHandlerExceptionResolvers的处理⽅式⼏乎 都⼀样(4,5,6) 1.初始化⽂件上传解析器MultipartResolver 从应⽤上下⽂中获取名称为multipartResolver的Bean如果没有名为multipartResolver的Bean则没有提供上传⽂件的解析器 2.初始化区域解析器LocaleResolver 从应⽤上下⽂中获取名称为localeResolver的Bean如果没有这个Bean则默认使⽤AcceptHeaderLocaleResolver作为区域解析器 3.初始化主题解析器ThemeResolver 从应⽤上下⽂中获取名称为themeResolver的Bean如果没有这个Bean则默认使⽤FixedThemeResolver作为主题解析器 4.初始化处理器映射器HandlerMappings 处理器映射器作⽤1通过处理器映射器找到对应的处理器适配器将请求交给适配器处理2缓存每个请求地址URL对应的位置Controller.xxx⽅法如果在ApplicationContext发现有HandlerMappings则从ApplicationContext中获取到所有的HandlerMappings并进⾏排序如果在ApplicationContext中没有发现有处理器映射器则默认BeanNameUrlHandlerMapping作为处理器映射器 5.初始化处理器适配器HandlerAdapter 作⽤是通过调⽤具体的⽅法来处理具体的请求如果在 ApplicationContext发现有handlerAdapter则从ApplicationContext中获取到所有的HandlerAdapter并进⾏排序如果在ApplicationContext中没有发现处理器适配器则默认 SimpleControllerHandlerAdapter作为处理器适配器 6.初始化异常处理器解析器HandlerExceptionResolver 如果在ApplicationContext发现有 handlerExceptionResolver则从ApplicationContext中获取到所有的HandlerExceptionResolver并进⾏排序如果在ApplicationContext中没有发现异常处理器解析器则不设置异常处理器 7.初始化RequestToViewNameTranslator 其作⽤是从Request中获取viewName从ApplicationContext发现有viewNameTranslator的Bean如果没有则默认使⽤DefaultRequestToViewNameTranslator 8.初始化视图解析器ViewResolvers 先从ApplicationContext中获取名为viewResolver的Bean如果没有则默认InternalResourceViewResolver作为视图解析器 9.初始化FlashMapManager 其作⽤是⽤于检索和保存FlashMap保存从⼀个URL重定向到另⼀个URL时的参数信息从ApplicationContext发现有flashMapManager的Bean如果没有则默认使⽤DefaultFlashMapManager 1.2 处理请求(核心) DispatcherServlet 接收到请求后, 执⾏doDispatch 调度⽅法, 再将请求转给Controller. 我们来看doDispatch ⽅法的具体实现 protected void doDispatch(HttpServletRequest request, HttpServletResponseresponse) throws Exception {HttpServletRequest processedRequest request;HandlerExecutionChain mappedHandler null;boolean multipartRequestParsed false;WebAsyncManager asyncManager WebAsyncUtils.getAsyncManager(request);try {try {ModelAndView mv null;Exception dispatchException null;try {processedRequest this.checkMultipart(request);multipartRequestParsed processedRequest ! request;//1. 获取执⾏链//遍历所有的 HandlerMapping 找到与请求对应的HandlermappedHandler this.getHandler(processedRequest);if (mappedHandler null) {this.noHandlerFound(processedRequest, response);return;}//2. 获取适配器//遍历所有的 HandlerAdapter找到可以处理该 Handler 的HandlerAdapterHandlerAdapter ha this.getHandlerAdapter(mappedHandler.getHandler());String method request.getMethod();boolean isGet HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {long lastModified ha.getLastModified(request,mappedHandler.getHandler());if ((new ServletWebRequest(request,response)).checkNotModified(lastModified) isGet) {return;}}//3. 执⾏拦截器preHandle⽅法if (!mappedHandler.applyPreHandle(processedRequest, response)){return;}//4. 执⾏⽬标⽅法mv ha.handle(processedRequest, response,mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}this.applyDefaultViewName(processedRequest, mv);//5. 执⾏拦截器postHandle⽅法mappedHandler.applyPostHandle(processedRequest, response, mv);} catch (Exception var20) {dispatchException var20;} catch (Throwable var21) {dispatchException new NestedServletException(Handlerdispatch failed, var21);}//6. 处理视图, 处理之后执⾏拦截器afterCompletion⽅法this.processDispatchResult(processedRequest, response,mappedHandler, mv, (Exception)dispatchException);} catch (Exception var22) {//7. 执⾏拦截器afterCompletion⽅法this.triggerAfterCompletion(processedRequest, response,mappedHandler, var22);} catch (Throwable var23) {this.triggerAfterCompletion(processedRequest, response,mappedHandler, new NestedServletException(Handler processing failed, var23));}} finally {if (asyncManager.isConcurrentHandlingStarted()) {if (mappedHandler ! null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}} else if (multipartRequestParsed) {this.cleanupMultipart(processedRequest);}}} HandlerAdapter 在 Spring MVC 中使⽤了适配器模式 适配器模式, 也叫包装器模式. 简单来说就是⽬标类不能直接使⽤, 通过⼀个新类进⾏包装⼀下, 适配调⽤⽅使⽤. 把两个不兼容的接⼝通过⼀定的⽅式使之兼容。 HandlerAdapter 主要⽤于⽀持不同类型的处理器如 Controller、HttpRequestHandler 或者 Servlet 等让它们能够适配统⼀的请求处理流程。这样Spring MVC 可以通过⼀个统⼀的接⼝来处理来⾃各种处理器的请求。 从上述源码可以看出在开始执⾏ Controller 之前会先调⽤ 预处理⽅法 applyPreHandle⽽ applyPreHandle ⽅法的实现源码如下 boolean applyPreHandle(HttpServletRequest request, HttpServletResponseresponse) throws Exception {for(int i 0; i this.interceptorList.size(); this.interceptorIndex i) {// 获取项⽬中使⽤的拦截器 HandlerInterceptorHandlerInterceptor interceptor (HandlerInterceptor)this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {this.triggerAfterCompletion(request, response, (Exception)null);return false;}}return true;} 在 applyPreHandle 中会获取所有的拦截器 HandlerInterceptor , 并执⾏拦截器中的 preHandle ⽅法这样就会咱们前⾯定义的拦截器对应上了如下图所⽰ 如果拦截器返回true, 整个发放就返回true, 继续执⾏后。 如果拦截器返回fasle, 则中断后续操作