doDispatch处理机制
这部分不是处理器模式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,分别为:
- RequestMappingHandlerAdapter,处理前端发起的HTTPRequest请求 -> HandlerMethod
- HttpRequestHandlerAdapter,处理HttpRequestHandler接口这种请求 ->比如Spring提供的WebSocket,及Socket JS等
- SimpleControllerHandlerAdapter,,处理Controller,是一个接口,不是@Controller。
掌握这种代码处理方式的几个点:
- 设定Adapter Interface,该interface支持两种操作,support和handle,support操作,判断该适配器是否能够支持对输入对象的操作,支持的,就对该输入对象进行对应处理。具体的适配动作,交由实现类去实现,以判断支持哪种操作并处理。
- 有一个Adapter集合,该集合存放了各种具体的适配器
- 循环遍历每种具体的适配器,判断每种适配器是否支持该对象的操作,具体结构为:
// 在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)
}
}