SpringMVC request processing adapter and processor source code analysis
What does SpringMVC do for you when an HTTP request comes in?
Last SpringMVC source analysis because of the length of the reason will only request mapper source process analysis completed, I do not know what you think of the last process analysis? Free time is not their own after a source!
First above:
Last article, I did a very detailed process analysis of the Handler processor mapper, so this article will be around the processor adapter, processor two processes to analyze the source!
1. Source code analysis of processor adapter
In fact, the last article also explained the general logic behind, but in fact, SpringMVC as an excellent framework, it is very comprehensive, in fact, there is not only one way to develop a Controller plus @Controller, there is also interface based implementation, How does SpringMVC feel about different processing methods, such as implementing the Colltroller interface and implementing the HttpRequestHandler interface? So, after SpringMVC finds the corresponding mapping method based on the request path, how can it tell if the method was created in one of the three ways? This is where the processor adapter comes in! Look at a piece of code!
// Get the details of the mapping method according to the request path
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Call the processor adapter to find the corresponding processor for this method
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
Copy the code
Let’s take a look at the logic inside the processor adapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters ! =null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
returnadapter; }}}throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
Copy the code
- First he loops a loop called
handlerAdapters
Where is this property set? There is one in the spring-webmVC.jar directory calledDisPatcherServlet.properties
“, internally defines three processors. Why three processors? As stated above, there are three ways to code controllers, so there are three corresponding processors!
- This method loops through all adapter schemes until the appropriate processor returns, or else is thrown
ServletException
Abnormal!
2. Processor source code parsing
When the handler returns, the next step is to take the handler and process our corresponding method! How do you deal with that? We went back to the original org. Springframework. Web. Servlet. DispatcherServlet# doDispatch method
We enter to code logic processor internal org. Springframework. Web. Servlet. MVC) method. The AbstractHandlerMethodAdapter# handle
Org. Springframework. Web. Servlet. MVC) method. The annotation. RequestMappingHandlerAdapter# handleInternal method (note here, we are in common Analysis by @controller registration)
So let’s look at some code
// Check whether the synchronization block needs to be moved (usually not set to synchronization)
// Sessions are not thread-safe. To ensure that the same session is accessed correctly across multiple requests, set synchronizeOnSession to TRUE.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if(session ! =null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) { mav = invokeHandlerMethod(request, response, handlerMethod); }}else {
// No HttpSession available -> no mutex necessarymav = invokeHandlerMethod(request, response, handlerMethod); }}else {
// Let's click inside to see the internal implementation of this method
mav = invokeHandlerMethod(request, response, handlerMethod);
}
Copy the code
invocableMethod.invokeAndHandle(webRequest, mavContainer); Method internal implementation!
Org. Springframework. Web. Method. Support. InvocableHandlerMethod# invokeForReques method implementation
- We can see that there is a logical code like this
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}
Copy the code
getMethodArgumentValues
Gets the parameters of the method, and the values passed
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// Get method argument list (parameter list)
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
// Build an array of parameter objects
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
// Get the parameter object
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if(args[i] ! =null) {
continue;
}
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// This method is used to obtain the corresponding parameters in the request object from the parameter name of the method and assign them to the corresponding parameter object
args[i] = this.resolvers.resolveArgument(parameter, mavContainer,
request, this.dataBinderFactory);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
String exMsg = ex.getMessage();
if(exMsg ! =null&&! exMsg.contains(parameter.getExecutable() .toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); }}throwex; }}// Returns all parameters and their values
return args;
}
Copy the code
doInvoke(Object… args)
- The processor starts executing the method reflectively, and the main logic of the execution is as follows:
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
returngetBridgedMethod().invoke(getBean(), args); }... Ignore.. }Copy the code
Get the method object, get the object instance from the Bean factory, pass the parameter to set the method, and get the method return value!
After get the return value, step by step back, back to the org. Springframework. Web. Servlet. MVC) method. The annotation. ServletInvocableHandlerMethod# invokeAndHandle method
Finally the method is invoked org. Springframework. Web. Servlet. MVC) method. The annotation. RequestResponseBodyMethodProcessor# handleReturnValue
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
Copy the code
Finally through writeWithMessageConverters (returnValue, returnType inputMessage, outputMessage); Write the execution results to the page (actually Servlet development is the same logic, but SpringMvc layer encapsulation optimization)!
It is not hard to see SpringMvc intercepting request to processing request mapping method, although I am not finished, but can summarize a little:
If the understanding of the article is wrong, welcome big men private chat correction! Welcome to pay attention to the author’s public number, progress together, learn together!