Click on the blue letters above to follow us
01
preface
The cause of the matter is that microservice A calls one of the interfaces of microservice B through feign and reports an exception in the following shape
Xiao Zhang, the engineer in charge of microservice A, found Xiao Li, the engineer responsible for providing the interface, and asked Xiao Li if he had changed the interface, Xiao Li said with an innocent face that he had not made any changes to this interface recently, but Xiao Li still said that he checked it.
02
Troubleshooting process
Xiao Li’s troubleshooting process is as follows, he first checks whether the interface he provides to A service exists through swagger, and he finds that he cannot see the interface he provides to A service on swagger. So he doubted whether someone had moved his code, he went to look up the recent git commit record, found that no one touched his code, because the project has not yet been released, all in the testing stage, he will be based on the project integration of git-commit-id-maven-plugin plugin to test which version of the current release is. (ps: Friends who are interested in git-commit-id-maven-plugin can check out the previous article on how to verify that the online version is in line with the expected version). Then he put the version of the code down to the local debugging, he found that the interface provided to A in the code is still there, the class under the target also has an interface class provided to A, but the strange thing is that swagger is not showing the interface he provided out, he once thought that swagger had a problem, so he used postman to directly ask him to provide A’s interface, found that 404. Then he called Xiao Wang, a colleague in charge of the same microservice B, to help try it out, and found that the result was 404. After the recruitment, Xiao Li went to ask for help from their senior colleague Xiao Lin.
Kobayashi’s troubleshooting idea is as follows, he first looked up Xiao Li’s interface code, and found that he added a @Async to the method of the interface implementation layer he provided, and the example is as follows
Xiao Lin intuitively told Xiao Li with years of experience that it should be caused by @Async. Xiao Li said very categorically that it was impossible, he @Async added very early, before the interface can be accessed, Xiao Lin saw Xiao Li said so sure, he is not good at hitting Xiao Li. So he next did the following operation, first configure the following parameters in the project yml, and open the springweb log
Then add code in the project that looks like the following to track the type of the interface bean
Start the console and see the log shape as follows
It was found that the relevant requestMapping mapping information was indeed not printed, which can explain that Xiao Li’s interface was not bound to the springmvc mapping, which is the reason for the emergence of 404. Then observe the bean printed by the console, which looks like this
It is obvious that this interface bean has been replaced by the jdk dynamic proxy. Xiao Li saw the information printed on the console, thought about it, and then said, I removed the @Async and tried it. Xiao Li removed the @Async and then looked at the console
Through the console, it can be found that the interface has been bound to the springmvc mapping, and the printed bean type is a real object bean. Xiao Li saw this phenomenon and was puzzled, he said that he had indeed added @Async before, and the interface could be accessed normally. So Xiaolin asked, are you sure that you added @Async, did asynchronous take effect, Xiao Li said to open spring asynchrony, isn’t it all @Async. Xiaolin asked again, you open asynchronous in the project, in addition to adding @Async, what else to do, Xiao Li said no, he used asynchronous in the project before he added @Async, can also use a good one, Xiaolin listened, basically know why Xiao Li @Async before, the interface can be accessed normally, Xiaolin in order to verify the idea, just ask Xiao Wang who is responsible for the project, said that you have recently added any asynchronous operations, Xiao Wang said there is, Xiao Lin further asked, how do you do it, Xiao Wang said, He first adds @EnabledAsyn, turns on asynchrony, and then adds @Async annotations to the methods at the business logic layer. Xiao Li listened and said that he had to cooperate with @Async when he used @EnabledAsyn, he didn’t know it before
Then Xiao Li said that in the controller can not use @Async annotations? , Kobayashi said that it is best to move the logic of adding @Async to the service layer to deal with, but it is not that the controller cannot use the @Async annotation, and then Kobayashi in order to verify this idea, he removed the original implementation of the interface class, the shape is as follows
After launching, view the console
At this point, the type of bean is as follows
Provider, print the following contents
From the console, it can be found that it is triggered by the http-nio-8080-exec-1 thread, indicating that the async does not take effect, that is, the @Async fails. Later, the controller was modified as follows
Provider, print the following contents
This shows that in the controller, you can actually use @Async, but you have to do extra processing. So the suggestion is to take the @Async out of the controller and process it in a new class, as shown below
Provider, print content
Description Asynchronous effect
03
Analysis of troubleshooting results
01
Interface 404
Log from mvc
We can know that the controller mapping processing is in the RequestMappingHandlerMapping class, but which method is the specific method to process, we can reverse the information printed by the log, or we can add breakpoint debugging based on the spring feature, such as debugging through the afterPropertiesSet extension point. You will find that the mapping processing of RequestMappingHandlerMapping is in
Processing, specifically through processCandidateBean
Ultimately, it is handled by detectHandlerMethods
This is the actual registration. The premise of implementing detectHandlerMethods is
That is, only the class with the added @Controller or @RequestMapping will be processed, and why @RestController is also processed, click @RestController discovery
He is essentially @Controller. But we look for annotations through reflection, and normally only look for one layer, for example
He finds the @RestController layer instead of continuing to look for @RestController inside the @Controller, and AnnotatedElementUtils.hasAnnotation, this annotation method is different, he can find the merged annotation, even if it is @RestController, he will continue to find the @Controller inside. Therefore, this method is useful for finding composite annotations
When we use the jdk dynamic proxy, because there is no @Controller or @RequestMapping on the parent class, it will not be mapped by mvc, resulting in 404. When using cglib, because he inherits the target class as a subclass, he inherits the annotations on the target class, so when it is a cglib proxy, he will be mapped normally by mvc
02
Why is the controller added @Asyn asynchronous invalid
This is because with the addition of @Async, the controller becomes a proxy, and when it comes to processing methods asynchronously, it uses the target object, not the proxy object. This is basically a routine with the current interview affairs why the affairs are invalid
04
summary
This article focuses @Async causes the controller 404 to fail @Async. The recommended solution is to extract the @Async out of the controller and create a new service class for processing.