前言

在分析问题前,先看下Tomcat的架构图,有助于后面看代码:

java中controller接口能相互调用吗 接口怎么调用controller_java

这里可以看出一个Tomcat就是一个Server,一个Server下会有多个Service,Service只负责封装多个Connector和一个Container(Service本身不是容器,可以看做只是用来包装Connector和Container的壳,不负责具体功能),而Container(也叫engine)下又有多个Host,每个Host下对应多个Context,Context下才是我们的Servlet,Tomcat为了使整个架构灵活,所以抽象出这么多层,每层之间都可以根据不同的维度产生一对多个配置。

源码分析

DispatcherServlet用来处理请求的主要流程图如下:

java中controller接口能相互调用吗 接口怎么调用controller_servlet_02

结合流程图看下代码:

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.
				// 1、遍历已经配置的HandlerMapping列表,调用HandlerMapping的getHandler方法,获取当前Request对象所对应的处理链HandlerExecutionChain,HandlerExecutionChain对象封装了处理这个Request的所有Interceptor及这个处理这个Request的HandlerMethod对象
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				// 2、根据1步中的HandlerMethod获取对应的HandleAdapter
				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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
        // 3、开始逐个调用第28步中获取的调用链中的interceptor的PreHandle方法,如果需要拦截,则流程被拦截,直接返回
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				// 4、调用第29步中的HandlerAdapter的handle方法处理请求,这里会去请求Controller里的接口,Controller里的方法已经被包装成HandleMethod对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

				applyDefaultViewName(processedRequest, mv);
				// 逐个调用拦截器的postHandle方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			// 处理modelAndView对象,解析视图,比如html、jsp对象等
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", 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);
				}
			}
		}
	}

根据流程图 这里出现了几个重要的类HandlerMapping、HandlerExecutionChain、HandlerMethod、HandlerAdapter、HandlerMethodReturnValueHandler,解释下这几个类:

HandlerMapping:该类提供了通过request匹配到对应HandlerExecutionChain的能力,可以理解为一个映射类

HandlerExecutionChain:封装了用来处理请求的调用链,包括所有的拦截器以及用来处理请求的Handler,这里就是封装了Controller方法信息的HandlerMethod

HandlerMethod:封装了用来处理请求的类及方法的元数据信息,包括类、方法以及是spring管理的哪个bean(这里可以理解成是spring管理的那个controller对象)

java中controller接口能相互调用吗 接口怎么调用controller_servlet_03

HandlerAdapter:Handler的适配器,在调用Controller方法场景下,这里的Handler就是HandlerMethod,这个接口的方法有三个:

public interface HandlerAdapter {

  // 判断当前HandlerAdapter是否支持handler,比如Controller场景下的,这个handler就是HandlerMethod对象
	boolean supports(Object handler);

	// 处理请求
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;


	long getLastModified(HttpServletRequest request, Object handler);

}

HandlerMethodReturnValueHandler:处理返回结果,Controller场景下就是处理 Controller里接口返回结果的

比如我有个Controller,代码如下:

@RestController
@RequestMapping("/api")
public class HelloController {

    @RequestMapping("/hello")
    public String hello() {
        return "hello2";
    }

}

我们看下在我请求这个接口,这几个重要步骤是怎么处理的:
第一步、getHandler()debug图:

java中controller接口能相互调用吗 接口怎么调用controller_spring_04

这个Controller里的接口已经被解析并保存在这个mapping中,debug截图如下:

java中controller接口能相互调用吗 接口怎么调用controller_sed_05

在构建这个调用链时,会包含我们的拦截器:

java中controller接口能相互调用吗 接口怎么调用controller_servlet_06

第二步、getHandlerAdapter(handler)debug图:

java中controller接口能相互调用吗 接口怎么调用controller_sed_07

第三步、执行调用链中interceptor的PreHandle方法

java中controller接口能相互调用吗 接口怎么调用controller_sed_08

第四步、adapter的handleInternal方法

这个截图可以看到我们的Controller方法已经被封装成HandlerMethod对象,包含bean、method等信息

java中controller接口能相互调用吗 接口怎么调用controller_sed_09

第五步、HandlerMethodReturnValueHandler处理返回结果

java中controller接口能相互调用吗 接口怎么调用controller_servlet_10

这里可以看到有很多HandlerMethodReturnValueHandler,通过HandlerMethodReturnValueHandler.supportsReturnType()来匹配,我们这里返回的是RequestResponseBodyMethodProcessor对象,通过代码可以看出如果方法被@ResponseBody注解注释,那么就使用这个类来处理返回值。

@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
				returnType.hasMethodAnnotation(ResponseBody.class));
	}
	
	// 处理返回值
	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
    // 设置requestHandled为true,表示请求已经处理完毕,后续不需要再做处理,比如解析view视图等逻辑
		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

		// Try even with null return value. ResponseBodyAdvice could get involved.
		// 调用ResponseBodyAdvice来处理返回值,并将最终结果写到response的输出流中
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

第六步、解析modelAndView对象

由于这里没有返回视图对象,所以没有做处理,如果你接口里需要返回一个html或者jsp,那么就是这个地方来解析你的View对象

java中controller接口能相互调用吗 接口怎么调用controller_tomcat_11

最后贴一张tomcat处理请求的完整流程图:

java中controller接口能相互调用吗 接口怎么调用controller_tomcat_12