Giống như các servlet khác, để DispatcherServlet có thể nhận được và xử lý request, chúng ta cần phải cấu hình để web server container có thể khởi tạo và ánh xạ URL cho nó. Trong bài viết này, mình sẽ giới thiệu với các bạn cách khởi tạo và cấu hình DispatcherServlet trong Spring MVC!
Để làm ví dụ, mình sẽ sử dụng project mà mình đã tạo ở bài viết trước, cấu trúc project của mình như sau:
Với Servlet 3.0, chúng ta có một số cách để cấu hình và đăng ký một servlet như:
- Sử dụng tập tin web.xml.
- Sử dụng tâp tin web-fragment.xml.
- Sử dụng javax.servlet.ServletContainerInitializer.
Spring MVC còn cho phép chúng ta sử dụng the org.springframework.web.WebApplicationInitializer để cấu hình và đăng ký một servlet.
Nhưng trong project ví dụ, chúng ta đang sử dụng cách phổ biến đó là sử dụng một tập tin web.xml nên trong bài viết này mình chỉ đề cập đến cách này. Nội dung của tập tin web.xml như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- The definition of the Root Spring Container shared by all Servlets and Filters --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> <!-- Creates the Spring Container shared by all Servlets and Filters --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Processes application requests --> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> |
Các bước để khởi tạo và cấu hình cho DispatcherServlet bao gồm:
- Đăng ký khởi tạo DispatcherServlet trong web server container và ánh xạ URL.
- Sau khi khởi tạo xong, DispatcherServlet sẽ sử dụng org.springframework.web.context .WebApplicationContext để cấu hình cho nó.
Chúng ta sẽ đi vào chi tiết từng bước các bạn nhé!
Khởi tạo và ánh xạ URL cho DispatcherServlet
Giả sử chúng ta chưa có tập tin web.xml trong project của chúng ta đi, thì bắt buộc các bạn phải tạo mới một tập tin web.xml nằm trong thư mục /src/webapp/WEB-INF. Đây là tập tin sẽ chứa tất cả các cấu hình web server container cần để khởi tạo servlet, listener hay filter.
Và để khởi tạo và ánh xạ URL cho DispatcherServlet các bạn chỉ cần khai báo như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- Processes application requests --> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> |
Mặc định khi DispatcherServlet được khởi tạo, nó sẽ khởi tạo một đối tượng org.springframework.web.context.WebApplicationContext với hiện thực là org.springframework.web.context.support.XmlWebApplicationContext. Đối tượng XmlWebApplicationContext này chứa cấu hình tất cả các beans mà chúng ta sẽ định nghĩa trong khung chứa của Spring. Đối tượng này sẽ sử dụng một tập tin cấu hình của Spring với tên gọi mặc định là [tên-servlet]-servlet.xml nằm trong thư mục /src/webapp/WEB-INF.
Nếu các bạn không định nghĩa tập tin cấu hình của Spring này thì khi chạy ứng dụng web của chúng ta, lỗi sẽ xảy ra:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/appServlet-servlet.xml] at org.springframework.web.context.support.ServletContextResource.getInputStream(ServletContextResource.java:140) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:328) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:131) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:522) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:436) at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:631) at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:588) at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:645) at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:508) at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:449) at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:133) |
Ở đây, mình sẽ không định nghĩa tập tin này, vì chúng ta có thể sử dụng DispatcherServlet để định nghĩa tập tin cấu hình của Spring.
Cấu hình DispatcherServlet
Để thêm tập tin cấu hình của Spring, các bạn có thể sử dụng thuộc tính contextConfigLocation của DispatcherServlet và cấu hình nó trong tập tin web.xml như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- Processes application requests --> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> |
Giá trị của thuộc tính contextConfigLocation chính là đường dẫn đến tập tin cấu hình cho Spring của chúng ta.
Cấu hình root servlet
Nhìn lại tập tin web.xml trong project ví dụ của chúng ta, các bạn sẽ thắc mắc những dòng cấu hình sau dành cho mục đích gì?
1 2 3 4 5 6 7 8 9 10 |
<!-- The definition of the Root Spring Container shared by all Servlets and Filters --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> <!-- Creates the Spring Container shared by all Servlets and Filters --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> |
Như các bạn đã biết, chúng ta có thể định nghĩa nhiều servlet trong một tập tin web.xml. Mỗi servlet có thể được khởi tạo, ánh xạ đến các URL khác nhau. Và do đó, chúng ta sẽ có nhiều Spring container tương ứng với từng servlet, với định nghĩa khác nhau.
Trong trường hợp đó, một số định nghĩa bean có thể lặp đi lặp lại trong nhiều Spring container. org.springframework.web.context.ContextLoaderListener được tạo ra để giải quyết vấn đề lặp đi lặp lại này bằng cách tạo ra một root org.springframework.web.context.WebApplicationContext sử dụng chung cho tất cả các servlet. ContextLoaderListener sẽ sử dụng tập tin được định nghĩa trong contextConfigLocation của thẻ <context-param>.
Trong tập tin root-context.xml, chúng ta sẽ định nghĩa các bean, các thuộc tính dùng chung giữa các khung chứa của Spring, mỗi khung chứa Spring trong mỗi servlet sẽ sử dụng các bean, các thuộc tính này cùng với những bean, những thuộc tính được định nghĩa riêng cho chính nó.
congptc
Bài viết của bạn rất hay và rất chi tiết , nhờ blog của bạn mà mình đã hiểu thêm rất nhiều về spring và java
Mong rằng bạn sẽ tiếp tục ra thêm những bài viết mới trong thời gian tới !
Cảm ơn bạn rất nhiều về những kiến thức bổ ích bạn đã chia sẻ .
Chúc bạn luôn mạnh khoẻ , và thành công 🙂
Khanh Nguyen
Cảm ơn bạn 🙂
Minh
Em chào anh , Anh ơi ! anh có thể đưa ra file dispatcherservlet và giải thích rõ từng tag trong đó giúp được không ạ ? em cảm ơn
Khanh Nguyen
Bạn đang thắc mắc gì nhỉ? Bạn không hiểu chỗ nào thì hỏi nhé!