- vừa được xem lúc

Spring Boot In Action: 404 not found.

0 0 24

Người đăng: logbasex

Theo Viblo Asia

I. Giới thiệu

Tình huống xảy ra được miêu tả như dưới đây.

Đầu tiên bạn có một Spring Application với cấu trúc thư mục như sau:

Và được run thành công ready trên port 8487:

Tuy nhiên khi bạn thực hiện việc gọi API thì HTTP response status là 404? Ủa 😂😂?

II. Phân tích vấn đề

Chúng ta muốn biết vì sao xảy ra lỗi 404 thì chúng ta phải hình dung được flow của một HTTP request thực thi trong ứng dụng Spring Boot như thế nào trước.

Khi Spring Boot application nhận được một HTTP request thì có một thằng gọi là DispatcherServlet sẽ dispatching những request này đến các Controller tương ứng. Sau khi tìm được Controller sẽ phải tìm một handler method có thể handle request đó. Nếu tìm thấy handler method phù hợp thì DispatcherServlet sẽ gọi handler method và trả về response.

Handler method ở đây là method được annotated với @RequestMapping annotation hay @GetMapping annotation với HTTP request method (GET/POST..) và path cụ thể.

#1
@RequestMapping(value = "/404", method = RequestMethod.GET)
public Object demo404NotFound(){ return "404 not found";
} #2
@GetMapping("/404")
public Object demo404NotFound(){ return "404 not found";
}

Tuy nhiên để một request gọi được vào ứng dụng thì Spring Boot cần có một vài bước tiền xử lý trong quá trình startup application như là initHandlerMethods. Phương thức initHandlerMethods chịu trách nhiệm cho việc khởi tạo tất cả mọi handler methods trong Spring Boot.

Phương thức này ban đầu sẽ đi tìm những beans trong ApplicationContext annotated với @Controller annotation hay chứa @RequestMapping annotation. Đến đây nếu để ý chúng ta sẽ phát hiện ra nguyên nhân gây nên lỗi 404 kể trên đó là _404Controller bean không được tìm thấy và đây chính là thủ phạm.

Nhưng chúng ta sẽ không chỉ dừng phân tích lại ở đó, sau khi phương thức initHandlerMethods tìm được bean thõa mãn yêu cầu như @Controller/ @RestController.. thì với mỗi bean tìm được, phương thức đi tìm tiếp những method annotated với @RequestMapping annotation và add vào registry để sử dụng.

private final Map<T, MappingRegistration<T>> registry = new HashMap<>();

Callstack

register:654, AbstractHandlerMethodMapping$MappingRegistry (org.springframework.web.servlet.handler)
registerHandlerMethod:332, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
registerHandlerMethod:420, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
registerHandlerMethod:76, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
lambda$detectHandlerMethods$2:299, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
accept:-1, 10885570 (org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$$Lambda$526)
forEach:684, LinkedHashMap (java.util)
detectHandlerMethods:297, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
processCandidateBean:266, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
initHandlerMethods:225, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
afterPropertiesSet:213, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
afterPropertiesSet:205, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
invokeInitMethods:1863, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
initializeBean:1800, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:620, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:542, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
lambda$doGetBean$0:335, AbstractBeanFactory (org.springframework.beans.factory.support)
getObject:-1, 1896232624 (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$227)
getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:333, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:208, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:955, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:918, AbstractApplicationContext (org.springframework.context.support)
refresh:583, AbstractApplicationContext (org.springframework.context.support)
refresh:147, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:734, SpringApplication (org.springframework.boot)
refreshContext:408, SpringApplication (org.springframework.boot)
run:308, SpringApplication (org.springframework.boot)
run:1306, SpringApplication (org.springframework.boot)
run:1295, SpringApplication (org.springframework.boot)
main:14, SpringBean404Application (com.logbasex)

Sau khi xong phần startup application và initHandlerMethods thì chúng ta sẽ tiến hành cắm debugging point ở controller và call API để xem cách Spring Boot nhận và xử lý HTTP request như thế nào.

Callstack:

createWithResolvedBean:372, HandlerMethod (org.springframework.web.method)
getHandlerInternal:384, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
getHandlerInternal:125, RequestMappingInfoHandlerMapping (org.springframework.web.servlet.mvc.method)
getHandlerInternal:67, RequestMappingInfoHandlerMapping (org.springframework.web.servlet.mvc.method)
getHandler:498, AbstractHandlerMapping (org.springframework.web.servlet.handler)
getHandler:1264, DispatcherServlet (org.springframework.web.servlet)
doDispatch:1046, DispatcherServlet (org.springframework.web.servlet)
doService:963, DispatcherServlet (org.springframework.web.servlet)
processRequest:1006, FrameworkServlet (org.springframework.web.servlet)
doGet:898, FrameworkServlet (org.springframework.web.servlet)
service:655, HttpServlet (javax.servlet.http)
service:883, FrameworkServlet (org.springframework.web.servlet)
service:764, HttpServlet (javax.servlet.http)
internalDoFilter:227, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilter:53, WsFilter (org.apache.tomcat.websocket.server)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:100, RequestContextFilter (org.springframework.web.filter)
doFilter:117, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:93, FormContentFilter (org.springframework.web.filter)
doFilter:117, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:201, CharacterEncodingFilter (org.springframework.web.filter)
doFilter:117, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:189, ApplicationFilterChain (org.apache.catalina.core)
doFilter:162, ApplicationFilterChain (org.apache.catalina.core)
invoke:197, StandardWrapperValve (org.apache.catalina.core)
invoke:97, StandardContextValve (org.apache.catalina.core)
invoke:541, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:135, StandardHostValve (org.apache.catalina.core)
invoke:92, ErrorReportValve (org.apache.catalina.valves)
invoke:78, StandardEngineValve (org.apache.catalina.core)
service:360, CoyoteAdapter (org.apache.catalina.connector)
service:399, Http11Processor (org.apache.coyote.http11)
process:65, AbstractProcessorLight (org.apache.coyote)
process:890, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1789, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1191, ThreadPoolExecutor (org.apache.tomcat.util.threads)
run:659, ThreadPoolExecutor$Worker (org.apache.tomcat.util.threads)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:750, Thread (java.lang)

References

===

Thanks for reading.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tổng hợp các bài hướng dẫn về Design Pattern - 23 mẫu cơ bản của GoF

Link bài viết gốc: https://gpcoder.com/4164-gioi-thieu-design-patterns/. Design Patterns là gì. Design Patterns không phải là ngôn ngữ cụ thể nào cả.

0 0 302

- vừa được xem lúc

Học Spring Boot bắt đầu từ đâu?

1. Giới thiệu Spring Boot. 1.1.

0 0 277

- vừa được xem lúc

Cần chuẩn bị gì để bắt đầu học Java

Cần chuẩn bị những gì để bắt đầu lập trình Java. 1.1. Cài JDK hay JRE.

0 0 50

- vừa được xem lúc

Sử dụng ModelMapper trong Spring Boot

Bài hôm nay sẽ là cách sử dụng thư viện ModelMapper để mapping qua lại giữa các object trong Spring nhé. Trang chủ của ModelMapper đây http://modelmapper.org/, đọc rất dễ hiểu dành cho các bạn muốn tìm hiểu sâu hơn. 1.

0 0 194

- vừa được xem lúc

[Java] 1 vài tip nhỏ khi sử dụng String hoặc Collection part 1

. Hello các bạn, hôm nay mình sẽ chia sẻ về mẹo check String null hay full space một cách tiện lợi. Mình sẽ sử dụng thư viện Lớp StringUtils download file jar để import vào thư viện tại (link).

0 0 71

- vừa được xem lúc

Deep Learning với Java - Tại sao không?

Muốn tìm hiểu về Machine Learning / Deep Learning nhưng với background là Java thì sẽ như thế nào và bắt đầu từ đâu? Để tìm được câu trả lời, hãy đọc bài viết này - có thể kỹ năng Java vốn có sẽ giúp bạn có những chuyến phiêu lưu thú vị. DJL là tên viết tắt của Deep Java Library - một thư viện mã ng

0 0 139