Spring MVC中请求到处理方法之间的处理机制


这部分不是处理器模式Handler

	/**
	 * Process the actual dispatching to the handler.
	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
	 * to find the first that supports the handler class.
	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
	 * themselves to decide which methods are acceptable.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception in case of any kind of processing failure
	 */
	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 {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				// 这个方法包含了创建HandlerMethod和MethodInterceptor
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

RequestMappingHandlerMapping在MVC中扮演的角色及作用

在这里插入图片描述

RequestMappingHandlerMapping也是一个InitializingBean,初始化后,执行super.afterPropertiesSet();。在这步操作中完成initHandlerMethods。在这里,完成应用所有的Controller请求对应的处理方法的创建。
AbstractHandlerMethodMapping中的initHandlerMethods又从该servlet容器中获取所有的beanName,进行注册到MappingRegistry

	/**
	 * Scan beans in the ApplicationContext, detect and register handler methods.
	 * @see #isHandler(Class)
	 * @see #getMappingForMethod(Method, Class)
	 * @see #handlerMethodsInitialized(Map)
	 */
	protected void initHandlerMethods() {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for request mappings in application context: " + getApplicationContext());
		}
		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		for (String beanName : beanNames) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				Class<?> beanType = null;
				try {
					beanType = getApplicationContext().getType(beanName);
				}
				catch (Throwable ex) {
					// An unresolvable bean type, probably from a lazy bean - let's ignore it.
					if (logger.isDebugEnabled()) {
						logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
					}
				}
				// beanType用@Controller或者@RequestMapping注解过
				if (beanType != null && isHandler(beanType)) {
					detectHandlerMethods(beanName);
				}
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}

其内部类MappingRegistry在MVC中扮演的角色及作用
该类包含了请求信息RequestMappingInfo跟对应的方法之间的映射。因此,当获取到RequestMappingInfo时,就从这里找到对应的业务处理方法。

	public void register(T mapping, Object handler, Method method) {
	        // 获取写锁,这个写锁在其中的作用~
			this.readWriteLock.writeLock().lock();
			try {
				HandlerMethod handlerMethod = createHandlerMethod(handler, method);
				assertUniqueMethodMapping(handlerMethod, mapping);

				if (logger.isInfoEnabled()) {
					logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
				}
				this.mappingLookup.put(mapping, handlerMethod);

				List<String> directUrls = getDirectUrls(mapping);
				for (String url : directUrls) {
					this.urlLookup.add(url, mapping);
				}

				String name = null;
				if (getNamingStrategy() != null) {
					name = getNamingStrategy().getName(handlerMethod, mapping);
					addMappingName(name, handlerMethod);
				}

				CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
				if (corsConfig != null) {
					this.corsLookup.put(handlerMethod, corsConfig);
				}

				this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
			}
			finally {
				// 释放锁
				this.readWriteLock.writeLock().unlock();
			}
		}

既然有写锁场景(第一次访问Web应用时,初始化RequestMappingHandlerMapping对象时。),自然而然就有读锁场景,这种场景发生在前端发送一个http请求时。读写分离。

	/**
	 * 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 {
			HandlerMethod 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();
		}
	}

SimpleUrlHandlerMapping在MVC中扮演的角色及作用

处理的是HttpRequestHandler这种接口的请求,例如WebSocket或者SockJs等。

HandlerMethod在MVC中扮演的角色及作用

对一个类的Method和BeanFactory(为了获取该Method的bean对象)的封装。

HandlerExecutionChain在MVC中扮演的角色及作用

由一系列的HandlerMethod和HandlerInterceptors组成。也不是责任链模式,仅是一个封装类,仅为了能在doDispatch中通过获得HandlerExecutionChain,进而获得HandlerMethod和HandlerInterceptors。
不仅仅是一个封装类,更是一种设计模式,责任链模式。之前,之所以认为不是责任链模式,是觉得跟责任链模式的模板不一致,就没认为他是责任链模式,其实,这是责任链模式的变种形式。

HandlerAdapter在MVC中扮演的角色及作用【适配器模式】

在Spring MVC中,有三种HandlerAdapter,分别为:

  1. RequestMappingHandlerAdapter,处理前端发起的HTTPRequest请求 -> HandlerMethod
  2. HttpRequestHandlerAdapter,处理HttpRequestHandler接口这种请求 ->比如Spring提供的WebSocket,及Socket JS等
  3. SimpleControllerHandlerAdapter,,处理Controller,是一个接口,不是@Controller。

掌握这种代码处理方式的几个点:

  1. 设定Adapter Interface,该interface支持两种操作,support和handle,support操作,判断该适配器是否能够支持对输入对象的操作,支持的,就对该输入对象进行对应处理。具体的适配动作,交由实现类去实现,以判断支持哪种操作并处理。
  2. 有一个Adapter集合,该集合存放了各种具体的适配器
  3. 循环遍历每种具体的适配器,判断每种适配器是否支持该对象的操作,具体结构为:
    // 在Spring中,这种结构很好获得,利用applicationContext.getBeansOfType(Adapter.class)即可获得Map<String, Adapter.class>
    // 该逻辑放在一个类的构造完成后的初始化中。
    // 这种代码逻辑很好扩展,适用于扩展多种业务场景的处理。按照场景扩展代码,比如,我们的系统无人仓调度,适配多种仓库。
    // 交通管制这一部分,面向对象来处理。不同的仓库,会有不同的交通管制。
    // 比如,我们一个仓有高密度货架区,这时,只需要再实现支持高密度区域的Adapter即可。
    // 目前,我们的交通管制,支持三种,比如普通区域的交通管制;弧形转弯进入旋转区的交通管制;弧形转弯出旋转区的交通管制;处理对象是AGV。
    // 对AGV进行交通管制,后续可以让一个地图既支持部分区域的单向道路的交通管制,又可以支持其他区域的双向道路的交通管制;
    // 还可以支持高密度区域的对AGV的交通管制。
    // 这种代码结构还适用于另一种场景,比如订单的各种操作,冻结那一些。
    // @PostConstruct
    // public void init() { ... }
	for(Adapter adapter: adapters) {
		if (adapter.supports(inputObject)) {
			adapter.handle(inputObject)
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值