国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
SpringMVC 深度解析@RequestMapping(一)

    SpringMVC作為一個MVC框架,有控制層,當(dāng)我們在瀏覽器發(fā)出了一個請求,SpringMVC是怎么處理請求,而且通過請求找到對應(yīng)的類的方法?我們今天帶著這么問題來解析SpringMVC源代碼處理過程。

  我們在實(shí)現(xiàn)SpringMVC控制層時,標(biāo)示了請求路徑,并標(biāo)示請求地址對應(yīng)的哪個方法,源代碼如下:

  1. @Controller  
  2. @RequestMapping(value="/test")  
  3. public class TestController2 {  
  4.     @Autowired  
  5.     private TestService testService;  
  6.       
  7.     @RequestMapping(value="/index")  
  8.     public ModelAndView getIndex(Model model){  
  9.        ModelAndView mv = new ModelAndView();    
  10.           return mv;        
  11.     }  
  12. }  

    注解@RequestMapping是處理方法的映射。我們在類上面注解和方法上注解這樣會更加的清晰,我們在類上標(biāo)示更能清晰的知道這個路徑是請求這個類,并在方法上注解比較清楚的是請求哪個方法。例如:http://127.0.0.1:8080/test/index.jhtml。如圖所示:

     

  我們先介紹兩個比較重要的組件HandlerMapping和HandlerAdapter是@Contoller@RequestMapping注解的處理器, HandlerMapping是處理請求映射的處理器;HandlerAdapter適配器處理器(動態(tài)調(diào)用方法和處理參數(shù))。我們在XML配置文件中進(jìn)行配置這兩種處理器。代碼如下:

  

  1. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>  
  2. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">  

 一:我們通過解析SpringMVC處理請求深度解析,并介紹HandlerMapping映射處理器

  我們講到這個這個XML配置,找到@RequestMapping@Controller并封裝成RequestMappingInfo,為后面我們解析處理請求會比較清晰,我在這在補(bǔ)充一下,我們在初始化Bean時我們在上一篇有介紹過,對@RequestMapping注解處理這部分我們沒介紹,所以我在這里在補(bǔ)充一下,RequestMappingHandlerMapping間接實(shí)現(xiàn)了InitializingBean接口,如圖所示:


   RequestMappingHandlerMapping間接實(shí)現(xiàn)了InitializingBean接口重寫了afterPropertiesSet方法,初始化RequestMappingHandlerMapping時,會調(diào)用afterPropertiesSet方法,跟 <bean class="" init-method=""/>屬性init-method處理一樣。afterPropertiesSet調(diào)用了RequestMappingHandlerMappinginitHandlerMethods實(shí)現(xiàn)的。處理@RequestMapping的,我們這邊來分析一下它是怎么實(shí)現(xiàn)的。源代碼:

  1. protected void initHandlerMethods() {  
  2.     String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?  
  3.             BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :  
  4.             getApplicationContext().getBeanNamesForType(Object.class));  
  5.     for (String beanName : beanNames) {  
  6.         if (isHandler(getApplicationContext().getType(beanName))){  
  7.             <span style="color:#cc0000;">detectHandlerMethods(beanName);</span>  
  8.         }  
  9.     }  
  10.     handlerMethodsInitialized(getHandlerMethods());  
  11. }  
  12.   
  13. @Override  
  14. protected boolean isHandler(Class<?> beanType) {  
  15.     return ((AnnotationUtils.findAnnotation(beanType, <span style="color:#cc0000;">Controller.class</span>) != null) ||  
  16.             (AnnotationUtils.findAnnotation(beanType, <span style="color:#cc0000;">RequestMapping.class</span>) != null));  
  17. }          

 說明:

   (1isHandler這個方法是判斷是否被@Controller@RequestMapping標(biāo)記

   (2)如果有被@Controller@RequestMapping標(biāo)記,然后生成RequestMappingInfo實(shí)例注冊到緩存中,供我們在請求時通過URL能匹配找到。

我們來看怎么生成RequestMappingInfo實(shí)例注冊到緩存,由detectHandlerMethods這個方法實(shí)現(xiàn)的。源代碼如下:

  1. protected void detectHandlerMethods(final Object handler) {  
  2.     Class<?> handlerType =  
  3.             (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());  
  4.   
  5.     final Map<Method, T> mappings = new IdentityHashMap<Method, T>();  
  6.     final Class<?> userType = ClassUtils.getUserClass(handlerType);  
  7.     Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {  
  8.         public boolean matches(Method method) {  
  9.             T mapping = <span style="color:#cc0000;">getMappingForMethod(method, userType);</span>  
  10.             if (mapping != null) {  
  11.                 mappings.put(method, mapping);  
  12.                 return true;  
  13.             }  
  14.             else {  
  15.                 return false;  
  16.             }  
  17.         }  
  18.     });  
  19.   
  20.     for (Method method : methods) {  
  21.                        //注冊到緩存中  
  22.         <span style="color:#cc0000;">registerHandlerMethod(handler, method, mappings.get(method))</span>;  
  23.     }  
  24. }  
  25.   
  26.      
  27.   @Override  
  28. protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {  
  29.     RequestMappingInfo info = null;  
  30.               //查找該類下注解的@RequestMapping的所有方法  
  31.     RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);  
  32.     if (methodAnnotation != null) {  
  33.         RequestCondition<?> methodCondition = getCustomMethodCondition(method);  
  34.                       //創(chuàng)建RequestMappingInfo  
  35.         info = createRequestMappingInfo(methodAnnotation, methodCondition);  
  36.                       //對類進(jìn)行查找有沒有標(biāo)示@RequestMapping注解  
  37.         RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);  
  38.         if (typeAnnotation != null) {  
  39.             RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);  
  40.                                //成成RequestMappingInfo。類別和方法級別的RequestMapping注解進(jìn)行組合  
  41.             info = <span style="color:#ff0000;">createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);</span>  
  42.         }  
  43.     }  
  44.     return info;  
  45. }  
  46.   //設(shè)置RequestMappingInfo的屬性然后創(chuàng)建<span style="font-family: 宋體;">RequestMappingInfo</span>  
  47.  protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition) {  
  48.     String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());  
  49.     return new RequestMappingInfo(  
  50.             new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),  
  51.                     this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),  
  52.             new RequestMethodsRequestCondition(annotation.method()),  
  53.             new ParamsRequestCondition(annotation.params()),  
  54.             new HeadersRequestCondition(annotation.headers()),  
  55.             new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),  
  56.             new ProducesRequestCondition(annotation.produces(), annotation.headers(), getContentNegotiationManager()),  
  57.             customCondition);  
  58. }  

  

  當(dāng)我們在瀏覽器發(fā)送了http://127.0.0.1:8080/test/index.jhtml這樣的請求,SpringMVC注冊在web.xml中的前端轉(zhuǎn)發(fā)器DispatcherServlet接收,在這個之前,我們對initHandlerMappingsinitHandlerAdapters初始化,這個在上一篇有介紹過。接下來我們開始分析DispatcherServlet處理請求。

   DispatcherServlet是間接的繼承了HttpSevlet,由父類FrameworkServlet實(shí)現(xiàn)了doPost和doGet方法,然后在調(diào)用子類,DispatcherServletdoDispatch方法處理請求,實(shí)現(xiàn)了設(shè)計(jì)原則接口隔離原則。請求的包含了一些頭部的信息等,如圖所示:

  



 doDispatch方法的源代碼如下:

  
  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  2.            HttpServletRequest processedRequest = request;  
  3.                               //判斷是否是文件流請求  
  4.             processedRequest = checkMultipart(request);  
  5.                                //獲取了映射處理器,里面是通過請求的URL獲取對應(yīng)的類并獲取實(shí)例化的Bean,包裝成HandlerMethod  
  6.             mappedHandler = <span style="color:#990000;">getHandler(processedRequest, false);</span>  
  7.             if (mappedHandler == null || mappedHandler.getHandler() == null) {  
  8.                 noHandlerFound(processedRequest, response);  
  9.                 return;  
  10.             }  
  11.                               //獲取HandlerAdapter  
  12.             HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
  13.             String method = request.getMethod();  
  14.             boolean isGet = "GET".equals(method);  
  15.             if (isGet || "HEAD".equals(method)) {  
  16.                 long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
  17.                 if (logger.isDebugEnabled()) {  
  18.                     String requestUri = urlPathHelper.getRequestUri(request);  
  19.                     logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);  
  20.                 }  
  21.                 if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {  
  22.                     return;  
  23.                 }  
  24.             }  
  25.             try {  
  26.                mv = <span style="color:#cc0000;">ha.handle(processedRequest, response, mappedHandler.getHandler());</span>  
  27.             }  
  28.             applyDefaultViewName(request, mv);  
  29.             mappedHandler.applyPostHandle(processedRequest, response, mv);        
  30.             processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
  31.     }  
  32. }  
  33.   
  34.   
  35. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
  36.     for (HandlerMapping hm : this.handlerMappings) {  
  37.         HandlerExecutionChain handler = <span style="color:#990000;">hm.getHandler(request);</span>  
  38.         if (handler != null) {  
  39.             return handler;  
  40.         }  
  41.     }  
  42.     return null;  
  43. }  

說明:

  (1Spring3.1開始的版本,建議使用RequestMappingHandlerMappingRequestMappingHandlerAdapter,所以我們在XML配置了這個Bean組件。 List<HandlerMapping> handlerMappings里面存放的是映射處理器,Spring內(nèi)置了很多映射處理器,例如SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping,如圖所示:

   

  (2HandlerExecutionChain包含了處理該請求的處理器,還包含一系列可以攔截請求的攔截器。

   RequestMappingHandlerMapping也是繼承了AbstractHandlerMapping,getHandler具體實(shí)現(xiàn)是由AbstractHandlerMapping來實(shí)現(xiàn)的,源代碼如下:

    
  1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
  2.         Object handler = getHandlerInternal(request);  
  3.         if (handler == null) {  
  4.             handler = getDefaultHandler();  
  5.         }  
  6.         if (handler == null) {  
  7.             return null;  
  8.         }  
  9.         // Bean name or resolved handler?  
  10.         if (handler instanceof String) {  
  11.             String handlerName = (String) handler;  
  12.             handler = getApplicationContext().getBean(handlerName);  
  13.         }  
  14.         return <span style="color:#990000;">getHandlerExecutionChain(handler, request);</span>  
  15.     }  

說明:

     (1getHandlerInternal方法是處理映射的,獲取request獲取了請求路徑,然后找到對應(yīng)的RequestMappingInfo獲取了Controller類,并找到了對應(yīng)的方法。

     (2HandlerExecutionChain帶了一系列的interceptors

     

第一:getHandlerInternal方法是通過URL找到對應(yīng)的處理映射的,并找到對應(yīng)的Bean實(shí)例,我們通過源代碼分析是怎么處理的?

  getHandlerInternal方法源代碼如下:

  1. protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {  
  2.                //通過UrlPathHelper獲取request獲取了請求路徑  例如:test/index.jhtml  
  3.         String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);  
  4.         if (logger.isDebugEnabled()) {  
  5.             logger.debug("Looking up handler method for path " + lookupPath);  
  6.         }  
  7.                 //  
  8.         HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);  
  9.         if (logger.isDebugEnabled()) {  
  10.             if (handlerMethod != null) {  
  11.                 logger.debug("Returning handler method [" + handlerMethod + "]");  
  12.             }  
  13.             else {  
  14.                 logger.debug("Did not find handler method for [" + lookupPath + "]");  
  15.             }  
  16.         }  
  17.                //返回對handlerMethod 進(jìn)行設(shè)置已經(jīng)初始化Bean并設(shè)置屬性的handlerMethod   
  18.         return (handlerMethod != null ? handlerMethod.<span style="color:#990000;">createWithResolvedBean</span>() : null);  
  19.     }  
  20.      //對bean進(jìn)行初始化  
  21.    public HandlerMethod createWithResolvedBean() {  
  22.         Object handler = this.bean;  
  23.         if (this.bean instanceof String) {  
  24.             String beanName = (String) this.bean;  
  25.                          //獲取對應(yīng)的Bean  
  26.             handler = this.beanFactory.getBean(beanName);  
  27.         }  
  28.         return new HandlerMethod(this, handler);  
  29.     }  
  30.  //設(shè)置bean、還有beanFactory 、method、parameters 等屬性  
  31. private HandlerMethod(HandlerMethod handlerMethod, Object handler) {  
  32.         Assert.notNull(handlerMethod, "HandlerMethod is required");  
  33.         Assert.notNull(handler, "Handler object is required");  
  34.         this.bean = handler;  
  35.         this.beanFactory = handlerMethod.beanFactory;  
  36.         this.method = handlerMethod.method;  
  37.         this.bridgedMethod = handlerMethod.bridgedMethod;  
  38.         this.parameters = handlerMethod.parameters;  
  39.     }  

 說明:

1UrlPathHelper是分析請求的URLLookupPathForRequest(request)這個方法中有alwaysUseFullPath默認(rèn)是false使用相對路徑。

2lookupHandlerMethod通過URL查看映射到哪個方法和類,MultiValueMap<String, T> urlMap 存放的keyurl,valueRequestMappingInfo信息(params等),通過lookupPath查找對應(yīng)的RequestMappingInfo,然后通過RequestMappingInfoMap<T, HandlerMethod> handlerMethods查找對應(yīng)的HandlerMethod,并返回。MultiValueMap<String, T> urlMap這個緩存中是我們在最開始時有介紹,處理@RequestMapping@Controll 并封裝成RequestMappingInfo并放到緩存,如圖所示:



如果查找對應(yīng)的方法時,放到Match,里面有包含的HandlerMethod,如圖所示:

  


   然后通過HandlerMethodcreateWithResolvedBean方法實(shí)現(xiàn)了通過beanName獲取已經(jīng)初始化的 Bean。然后重新初始化HandlerMethod對象,并設(shè)置bean、還有beanFactory 、methodparameters 等屬性。


第二:HandlerExecutionChain 包含了一系列攔截器。會在調(diào)用Controller類對應(yīng)方法之前、處理完方法還沒返回視圖、返回視圖之后,這些動態(tài)加以攔截。

HandlerExecutionChain這個類屬性很很多添加一系列的攔截器,源代碼如下:

  1. public class HandlerExecutionChain {  
  2.     private HandlerInterceptor[] interceptors;  
  3.     private List<HandlerInterceptor> interceptorList;  
  4. }  

getHandler具體實(shí)現(xiàn)是由AbstractHandlerMapping中,在這個 方法中實(shí)現(xiàn)了加入了攔截器,我們在看一下我們怎么加入攔截器,源代碼如下:

  1. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {  
  2.         HandlerExecutionChain chain =  
  3.             (handler instanceof HandlerExecutionChain) ?  
  4.                 (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);  
  5.                 //添加攔截器  
  6.         <span style="color:#990000;">chain.addInterceptors(getAdaptedInterceptors());</span>  
  7.         String lookupPath = urlPathHelper.getLookupPathForRequest(request);  
  8.         for (MappedInterceptor mappedInterceptor : mappedInterceptors) {  
  9.             if (mappedInterceptor.matches(lookupPath, pathMatcher)) {  
  10.                 chain.addInterceptor(mappedInterceptor.getInterceptor());  
  11.             }  
  12.         }  
  13.   
  14.         return chain;  
  15.     }  
  16. }  

說明:

       我們在XML里沒配置自己的攔截器,所以這邊都是為空的。

       HandlerInterceptor攔截器接口,里面有三個方法:

     (1preHandle方法:請求處理之前執(zhí)行的這個方法,在Controller方法調(diào)用之前調(diào)用。例如:調(diào)用之前判斷是否有登陸。

     (2postHandle方法: 請求進(jìn)行處理之后,在Controller 方法調(diào)用之后執(zhí)行,會在DispatcherServlet 調(diào)用ModelView視圖之前調(diào)用。

     (3afterCompletion方法:是在DispatcherServlet 調(diào)用ModelView視圖之后調(diào)用。


     既然HandlerInterceptor是接口,我們可以自己實(shí)現(xiàn)一個類實(shí)現(xiàn)這個接口,這樣我們就自己定義自己的攔截器,然后加到SpringMVC攔截中?當(dāng)然可以。

    我們自己定義了一個類實(shí)現(xiàn)了HandlerInterceptor 接口,例如:public class myInterceptor implements HandlerInterceptor 然后重寫了這個3個方法。我們在XML配置這個類,把自己定義的攔截器加到SpringMVC攔截中。在配置文件加入了

  1. <span style="color:#990000;"><beans xmlns:mvc="http://www.springframework.org/schema/mvc"  
  2.      xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"></span>  
  3.  <mvc:interceptors>  
  4. <mvc:interceptor>  
  5.   <!--攔截哪個包下的類例如:-->  
  6.       <mvc:mapping path="/test/*"/>  
  7.       <bean class="test.myInterceptor "></bean>  
  8.     </mvc:interceptor>  
  9.   </mvc:interceptors>  

這樣就把我們定義好的攔截器加到SpringMVC的攔截器中。


到這里,我們對HandlerMapping映射處理器介紹完了,


二:我們通過解析SpringMVC處理請求深度解析,并介紹HandlerAdapter適配器處理器(動態(tài)調(diào)用方法和處理參數(shù))

  

HandlerAdapter處理HandlerMethod映射并返回了視圖和數(shù)據(jù)的對象。getHandlerAdapter獲取了我們在配置文件的如圖所示:

 

父類AbstractHandlerMethodAdapter實(shí)現(xiàn)的,我們先看一下 繼承關(guān)系,這種開封閉原則。如圖所示:



我們來看一下這個handle(processedRequest, response, mappedHandler.getHandler());動態(tài)的調(diào)用方法和處理參數(shù)的具體實(shí)現(xiàn)。源代碼如下:

  1. public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
  2.             throws Exception {  
  3.         return handleInternal(request, response, (HandlerMethod) handler);  
  4.     }  
  5.   
  6.   @Override  
  7.     protected final ModelAndView handleInternal(HttpServletRequest request,  
  8.             HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {  
  9.   
  10.         if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {  
  11.             // Always prevent caching in case of session attribute management.  
  12.             checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);  
  13.         }  
  14.         else {  
  15.             // Uses configured default cacheSeconds setting.  
  16.             checkAndPrepare(request, response, true);  
  17.         }  
  18.   
  19.         // Execute invokeHandlerMethod in synchronized block if required.  
  20.         if (this.synchronizeOnSession) {  
  21.             HttpSession session = request.getSession(false);  
  22.             if (session != null) {  
  23.                 Object mutex = WebUtils.getSessionMutex(session);、  
  24.                 synchronized (mutex) {  
  25.                     return invokeHandleMethod(request, response, handlerMethod);  
  26.                 }  
  27.             }  
  28.         }  
  29.          //動態(tài)的調(diào)用方法和處理參數(shù)  
  30.         return invokeHandleMethod(request, response, handlerMethod);  
  31.     }  

說明:

  通過HandlerAdapter動態(tài)的調(diào)用方法和處理參數(shù),調(diào)用方法。我們這邊具體怎么動態(tài)調(diào)用方法和處理參數(shù),并返回視圖,等下一章在具體的介紹,這里涉及也比較多。


總結(jié):

  (1) 當(dāng)我們在瀏覽器發(fā)送了http://127.0.0.1:8080/test/index.jhtml這樣的請求,SpringMVC注冊在web.xml中的前端轉(zhuǎn)發(fā)器DispatcherServlet接收時。

  (2)通過URL查看映射到哪個方法和類,MultiValueMap<String, T> urlMap 存放的keyurl,valueRequestMappingInfo信息(params等),RequestMappingInfo獲取了Controller類,并找到了對應(yīng)的方法。并包裝返回了HandlerMethod。

  (3)通過BeanName,到工廠獲取已經(jīng)初始化的Bean,然后重新初始化HandlerMethod對象,并設(shè)置bean、還有beanFactory 、method、parameters 等屬性。

   (4)對HandlerExecutionChain添加攔截器和handler然后返回HandlerExecutionChain

  (5)HandlerAdapter對HandlerExecutionChain進(jìn)行動態(tài)的調(diào)用方法會返回ModelAndView。



瀏覽器請求已經(jīng)獲取到了,也找到了對應(yīng)的類和方法,那怎么動態(tài)的請求方法和處理參數(shù)等,執(zhí)行完方法并返回ModelAndView等?,帶著這些問題我們繼續(xù)前進(jìn)。



本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
SpringMVC RESTful 性能優(yōu)化 | 新達(dá)達(dá)技術(shù)
詳解SpringMVC請求的時候是如何找到正確的Controller[附帶源碼分析]
SpringMVC+WebSocket的通用接口映射實(shí)現(xiàn)
SpringMVC源碼剖析(一)
別怕,手把手帶你撕、拉、扯下SpringMVC的外衣
springboot+攔截器+注解實(shí)現(xiàn)自定義權(quán)限控制
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服