In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-09 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/03 Report--
I. Preface
I believe that each of us will encounter such a problem in SpringMVC development: when our code runs normally, the returned data is in our expected format, such as json or xml, but once an exception occurs (such as NPE or array out of bounds, etc.), the returned content is indeed the exception stack information on the server side, resulting in that the returned data cannot be parsed by the client normally. Obviously, these are not the results we want.
We know that a more common system will involve control layer, service (business) layer, cache layer, storage layer and interface calls, etc., in which each link will inevitably encounter a variety of unpredictable exceptions to deal with. If each step is separated by try..catch, it will make the system very messy, poor readability and high maintenance cost; the common way is to implement unified exception handling, thus decoupling all kinds of exceptions from each module.
Second, common global exception handling
There are three main types of global exception handling common in Spring:
(1) Note ExceptionHandler
(2) inherit HandlerExceptionResolver interface
(3) Note ControllerAdvice
In the following explanation, we mainly take the HTTP error codes: 400 (invalid request) and 500 (internal server error) as examples to take a look at the test code and the returned results without any processing, as follows:
(figure 1: test code)
(figure 2: error return without exception)
2.1 Note ExceptionHandler
Annotation ExceptionHandler action object as a method, the easiest way to use is to put it in the controller file, the detailed annotation definition is no longer introduced. If there are multiple controller files in the project, you can usually implement the exception handling of ExceptionHandler in baseController, and each contoller inherits basecontroller to achieve the purpose of unified exception handling. Because it is quite common, the simple code is as follows:
(used by ExceptionHandler in figure 3:Controller)
When the exception is returned, the name of the class to which it belongs is added to facilitate everyone's memory and understanding. Run to see the results:
(figure 4: result after adding ExceptionHandler)
Advantages: ExceptionHandler is easy to understand and has no limited method format for exception handling
Disadvantages: because ExceptionHandler only works on methods, in the case of multiple controller, for the sake of one method, all controller that need exception handling inherit this class. It is not good to force them to find a father for things that are obviously irrelevant. 2.2 Note ControllerAdvice
Although this is a ControllerAdvice annotation, it is actually a combination of it and ExceptionHandler. As you can see above, when using @ ExceptionHandler alone, it must be in a Controller, but there is no restriction when it is used in combination with ControllerAdvice. In other words, the combination of the two achieves global exception capture handling.
(figure 5: annotating ControllerAdvice exception handling code)
Before running, you need to comment out the ExceptionHandler in the previous Controller. The test results are as follows:
(figure 6: annotated ControllerAdvice exception handling results)
As you can see from the above results, exception handling has indeed been changed to the ExceptionHandlerAdvice class. This method integrates all exception handling into one place, removes the inheritance relationship in Controller, and achieves the effect of global capture. It is recommended to use this method.
2.3 implement the HandlerExceptionResolver interface
HandlerExceptionResolver itself is the internal interface of SpringMVC, and there is only one method in resolveException. By implementing this interface, we can achieve the purpose of global exception handling.
(figure 7: implementing the HandlerExceptionResolver interface)
Also before execution, comment out the exception handling of the above two methods, and the running result is as follows:
(figure 8: implementing the running result of the HandlerExceptionResolver interface)
You can see that 500 of the exception handling has taken effect, but 400 of the exception handling has not, and the root returns the same result before there is no exception. What's going on? Isn't it said that global exception handling can be achieved? There is no way to know the cause of the problem, we can only get to the bottom of the matter, to Spring's ancestral grave, below we combine Spring source code debugging, to need the reason.
Third, the source code analysis of exception handling in Spring
As we all know, the first class to receive a request in Spring is DispatcherServlet, and the core method in this class is doDispatch. We can break points in this class and follow up exception handling step by step.
3.1 HandlerExceptionResolver implementation class processing flow
Refer to the following follow-up steps. At the processHandlerException breakpoint, the tracking result is as follows:
(figure 9:processHandlerException breakpoint)
You can see that at the arrow [1] in the figure, the exception is handled by traversing the handlerExceptionResolvers, while at the arrow [2], you can see that there are four elements in the handlerExceptionResolvers, the last of which is the exception handling class defined by the 2.3method.
For the current request query request, based on the above phenomenon, it can be inferred that the exception handling should be handled in the first three exception handling, thus skipping our custom exception. With this guess, we F8 continue to follow up and can trace that the exception is handled by the third, that is, DefaultHandlerExceptionResolver.
DefaultHandlerExceptionResolver: SpringMVC is equipped with DefaultHandlerExceptionResolver by default. The doResolveException method of this class mainly handles some special exceptions and converts them into corresponding response status codes. The exception triggered by the query request is MissingServletRequestParameterException, which happens to be the exception targeted by DefaultHandlerExceptionResolver, so it will be caught by the exception in this class.
Now that the truth is clear, we can see that our custom class MyHandlerExceptionResolver can indeed handle exceptions globally, but the exception of the query request is intervened by DefaultHandlerExceptionResolver, so it skips the processing of the MyHandlerExceptionResolver class, resulting in a 400 return result. For calc requests, there is no blocking in the middle, so the desired results are achieved.
3.2 handling sequence of three types of exceptions
So far, we have introduced three types of global exception handling. According to the above analysis, we can see that the way to implement the HandlerExceptionResolver interface is the last, so who comes first in the order of @ ExceptionHandler and @ ControllerAdvice? Turn on all three types of exception handling (previously commented out), and run it to see the effect:
(figure 10: the result of all open exception handling)
As you can see from the phenomenon, the single @ ExceptionHandle exception handling in Controller ranks first, and @ ControllerAdvice ranks second. Strict children's shoes can write a Controller02, copy the query and calc, and forget the exception handling, so that when requesting the method of CO2, the class name of the exception catch is the class of @ ControllerAdvice.
The above are our conclusions based on the phenomenon, let's go to the Spring source code to find "evidence". In figure 9, there are four types of processors in handlerExceptionResolvers, and the processing of @ ExceptionHandler and @ ControllerAdvice is in the first ExceptionHandlerExceptionResolver (as you can see from the breakpoint follow-up). Continue to follow up until you enter the doResolveHandlerMethodException method of the ExceptionHandlerExceptionResolver class, where HandlerMethod is the method that Spring maps the HTTP request to the specified Controller, and Exception is the exception that needs to be caught; follow up to see what you have done with these two parameters.
(figure 11:doResolveHandlerMethodException breakpoint)
Continuing to follow up on the getExceptionHandlerMethod method, I found that two variables might be the crux of the problem: exceptionHandlerCache and exceptionHandlerAdviceCache. First of all, the variable names of the two are questionable; second, in the code, the former obviously uses the class as key to get a resolver, which coincides with the @ ExceptionHandler processing rules in Controller; finally, the processing order of the two Cache is also consistent with the previous conclusion. As previously guessed, Spring does give priority to finding the corresponding ExceptionHandler based on the Controller class name, and then handle the @ ControllerAdvice exception if it is not found.
(figure 12: two exception handling Cache)
If you are interested, you can continue to dig into the source code of Spring. Here is a brief summary of ExceptionHandlerExceptionResolver:
ExceptionHandlerCache contains ExceptionHandler exception handling in Controller. When handling, you can get Controller through HandlerMethod, and then find the exception handling method. It should be noted that it is the put value in the exception handling process.
ExceptionHandlerAdviceCache is initialized when the project starts. The general idea is to find the bean with @ ControllerAdvice annotation, so as to cache the ExceptionHandler in bean. When handling exceptions, you need to align the traversal lookup processing, so as to achieve the purpose of global processing. 3.3 salted fish turn over
After introducing so much, simply draw a picture and summarize it. The blue part is the three types of exception handlers added by Spring by default, and the × × part is the exception handling we added and the location and order in which it is called. To see where else is unclear, look back (ResponseStatusExceptionResolver is for the @ ResponseStatus annotation, which I won't go into more detail here).
(figure 13: exception summary)
If there is a need to deal with MyHandlerExceptionResolver in advance, or even ahead of ExceptionHandlerExceptionResolver, can it be done? The answer is yes. In Spring, if you want to handle MyHandlerExceptionResolver exceptions in advance, you need to implement another Ordered API and implement the getOrder method in it. Return-1 here, put it on top, and the salted fish can finally turn over this time.
(figure 14: implementing the Ordered interface)
Run to see if the results are in line with expectations, and remind you that all three exception handlers are effective, as shown in the following figure:
(figure 15: implementing the running result of the Ordered interface)
IV. Summary
This article mainly introduces three kinds of common global exception handling in SpringMVC, finds the problem in debugging, and then leads to go to the Spring source code to explore the cause, and finally solve the problem. I hope you can get something. Of course, Spring exception handling class is not only introduced these, interested children's shoes, please explore by yourself!
Reference link:
[1] http://www.cnblogs.com/fangjian0423/p/springMVC-request-mapping.html
[2] https://blog.csdn.net/mll999888/article/details/77621352
Author: Zhang Yuanhang
Source: Yixin Institute of Technology
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.