springMVC分析-2
springMVC的請求映射
上一次分析了一下springMVC的大致流程,這次細(xì)分一下,對請求映射進(jìn)行分析。
先從DispatcherServlet中的getHandler()方法分析
可以看到這是遍歷所有的handlerMappings然后第一個(gè)返回不是NULL的handler既是,那handlerMappings包含了那些實(shí)現(xiàn)類呢?我們來看看initHandlerMappings這個(gè)方法
private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;//detectAllHandlerMappings 默認(rèn)是trueif (this.detectAllHandlerMappings) {// 從ApplicationContext 里面獲取HandlerMapping的實(shí)現(xiàn)類Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);//根據(jù)Order對HandlerMappings進(jìn)行排序if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());// We keep HandlerMappings in sorted order.AnnotationAwareOrderComparator.sort(this.handlerMappings);}}else {try {//獲取bean name是handlerMapping的HandlerMapping實(shí)現(xiàn)類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.}}//若HandlerMappings為空,則設(shè)置默認(rèn)的在DispatcherServlet同級目錄下的DispatcherServlet.properties里面設(shè)置的org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterif (this.handlerMappings == null) {this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isDebugEnabled()) {logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");}} }所以若我們想使用自定義的HandlerMapping 可在springMVC的xml配置文件中加上一個(gè)HandlerMapping的實(shí)現(xiàn)類,若是使用的是 這個(gè)進(jìn)行配置的,其默認(rèn)會(huì)加載RequestMappingHandlerMapping這個(gè)實(shí)現(xiàn)類(具體在org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser見),而可以在web.xml中將detectAllHandlerMappings 設(shè)置為false,然后在springMVC.xml中配置一個(gè)name為handlerMapping的實(shí)現(xiàn)類。如下
// web.xml <servlet><servlet-name>myweb</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:mvc.xml</param-value></init-param><!-- 不加載所有的HandlerMapping的實(shí)現(xiàn)類的bean --><init-param><param-name>detectAllHandlerMappings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup> </servlet>//mvc.xml <bean name="handlerMapping" class="xxx具體實(shí)現(xiàn)類">繼續(xù)看handlerMapping是怎么根據(jù)request獲取到HandlerExecutionChain這個(gè)包含攔截器、具體處理的controller的,在AbstractHandlerMapping中以下方法
@Override public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {//獲取具體的處理類Object handler = getHandlerInternal(request);if (handler == null) {handler = getDefaultHandler();}if (handler == null) {return null;}// Bean name or resolved handler?if (handler instanceof String) {String handlerName = (String) handler;handler = getApplicationContext().getBean(handlerName);}//根據(jù)定義的Interceptors過濾出需要執(zhí)行的攔截器,聚合成HandlerExecutionChain這個(gè)執(zhí)行鏈HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);//CORS跨域請求if (CorsUtils.isCorsRequest(request)) {CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);executionChain = getCorsHandlerExecutionChain(request, executionChain, config);}return executionChain; }看getHandlerInternal(request) 這個(gè)方法,這個(gè)方法是個(gè)抽象方法,所以其實(shí)現(xiàn)在它的子類中,可以看出這個(gè)是一個(gè)模板模式,其在抽象類中定義出方法的骨架,而后某些方法交給子類實(shí)現(xiàn),這個(gè)方法有兩個(gè)實(shí)現(xiàn)類,AbstractHandlerMethodMapping,AbstractUrlHandlerMapping 這兩個(gè)具體實(shí)現(xiàn)類,我們先看AbstractHandlerMethodMapping 這個(gè)類實(shí)現(xiàn)的
/*** Look up a handler method for the given request.*/ @Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {//獲取請求路徑String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);if (logger.isDebugEnabled()) {logger.debug("Looking up handler method for path " + lookupPath);}//開啟讀鎖this.mappingRegistry.acquireReadLock();try {//獲取handlerMethodHandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);if (logger.isDebugEnabled()) {if (handlerMethod != null) {logger.debug("Returning handler method [" + handlerMethod + "]");}else {logger.debug("Did not find handler method for [" + lookupPath + "]");}}return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);}finally {//釋放鎖this.mappingRegistry.releaseReadLock();} }從這里可以看出 其最后處理的是一個(gè)HandlerMethod類,我們來看看這個(gè)類的結(jié)構(gòu)
public class HandlerMethod {private final Object bean;private final BeanFactory beanFactory;private final Class<?> beanType;private final Method method;private final Method bridgedMethod;private final MethodParameter[] parameters;private final HandlerMethod resolvedFromHandlerMethod; }可以看出其是一個(gè)聚合的類,里面包含了bean,method,故而其可以一個(gè)方法對應(yīng)一個(gè)請求。
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {List<Match> matches = new ArrayList<Match>();//根據(jù)請求路徑匹配List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);if (directPathMatches != null) {addMatchingMappings(directPathMatches, matches, request);}if (matches.isEmpty()) {// No choice but to go through all mappings...addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);}if (!matches.isEmpty()) {//最長路徑匹配原則Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));Collections.sort(matches, comparator);if (logger.isTraceEnabled()) {logger.trace("Found " + matches.size() + " matching mapping(s) for [" +lookupPath + "] : " + matches);}Match bestMatch = matches.get(0);if (matches.size() > 1) {if (CorsUtils.isPreFlightRequest(request)) {return PREFLIGHT_AMBIGUOUS_MATCH;}Match secondBestMatch = matches.get(1);if (comparator.compare(bestMatch, secondBestMatch) == 0) {Method m1 = bestMatch.handlerMethod.getMethod();Method m2 = secondBestMatch.handlerMethod.getMethod();throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");}}返回handlerMethodhandleMatch(bestMatch.mapping, lookupPath, request);return bestMatch.handlerMethod;}else {return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);} }AbstractHandlerMethodMapping 這個(gè)抽象類實(shí)現(xiàn)了InitializingBean接口,所以我們可以看看afterPropertiesSet()方法,其在實(shí)例化進(jìn)行的初始化操作,initHandlerMethods()方法,可以看出其在初始化時(shí),就初始化了HandlerMethod這個(gè)。
protected void initHandlerMethods() {// 獲取所有的BeanString[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :getApplicationContext().getBeanNamesForType(Object.class));for (String name : beanNames) {//判斷這個(gè)bean是否包含Controller,和RequestMapping這兩個(gè)注解if (!name.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(name))) {//將其注冊到MappingRegistrydetectHandlerMethods(name);}}//空方法handlerMethodsInitialized(getHandlerMethods()); }轉(zhuǎn)載于:https://www.cnblogs.com/myzhong2014/p/5310140.html
總結(jié)
以上是生活随笔為你收集整理的springMVC分析-2的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PinyinMatch实现拼音匹配,分词
- 下一篇: Android如何制作一个简易的视频播放