Deep into Spring Boot: Where did web.xml go?

Nowadays, web.xml is less and less used in the development of Spring-based web applications, or web.xml is basically invisible, so where is this web.xml? Next, let's explore together.

Use web.xml before Servlet3

Before Servlet3.0, web.xml was a file that must be configured for developing web applications. DispatcherServlet, ContextLoaderListener and other additional Servlets, Filters, and Listeners can be configured through it, just like the following web.xml configuration.

<?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">
	<display-name>web-app</display-name>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath*:spring/*.xml</param-value>
	</context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

	<servlet>
		<servlet-name>springMVC</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath*:springMVC.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

The above web.xml will create two Spring contexts when the application starts, one created by ContextLoaderListener and one created by DispatcherServlet. The context created by ContextLoaderListener is used to load beans related to non-web functions, such as Service, DAO, etc., while the context created by DispatcherServlet is used to load beans related to web functions, such as Controller and ViewResolver. The bean to be loaded in the context created by ContextLoaderListener comes from the xml specified by the contextConfigLocation configured by the context-param tag in web.xml, such as classpath : spring/ .xml; the bean to be loaded in the context created by DispatcherServlet comes from the configuration in web.xml The xml specified by the contextConfigLocation configured by the init-param tag in the DispatcherServlet, such as classpath*:springMVC.xml, if the contextConfigLocation is not configured by the init-param tag, the servlet-name configured by DispatcherServlet in web.xml is used as the prefix by default. -servlet.xml is the suffixed xml file, such as springMVC-servlet.xml.

Servlet3+ weakens web.xml

Servlet3.0 provides several new features on the basis of Servlet2.5 to simplify the development and deployment of Web applications. Added @WebServlet, @WebFilter and @WebListener in the javax.servlet.annotation package of servlet-api.jar Annotations are used to simplify the declaration of Servlets, filters, and listeners. That is to say, it is not necessary to use web.xml to develop web applications from now on. For example, the following code declares a custom Filter.

A javax.servlet.ServletContainerInitializer interface is provided in the Servlet3.0 API
. The interface has only one onStartup method. In a web application server that supports Servlet3.0, such as Tomcat7 or later, the server will be in the class path when it starts Find the implementation class of the javax.servlet.ServletContainerInitializer interface, and execute the onStartup method of the implementation class to configure the Servlet container, such as registering Servlet, Filter or Listener.

The onStartup method has two parameters: Set<Class<?>> c and ServletContext ctx, ServletContext is the Servlet context, which defines some methods for communicating with the Servlet container, and can also obtain some resource information of the web application; if the ServletContainerInitializer interface The implementation class of the @HandlesTypes annotation declares the class or interface of interest, then the implementation class of the class of interest and its subclasses or interfaces will be set to Set

The specific method of using the ServletContainerInitializer interface must define a file named javax.servlet.ServletContainerInitializer under the META-INF/services/ path under the classpath of the code. The content of this file is the full path of the ServletContainerInitializer interface implementation class, such as com.example .demo.MyServletContainerInitializer, the following implements a simple MyServletContainerInitializer.

As can be seen from the above figure, ServletContext provides methods to register Servlet, Filter and Listener, and register a Servlet and Filter dynamically below.

These new features of Servlet3.0 are weakening web.xml. Let's take a look at how Spring supports Servlet3.

Spring3+ gradually replaces web.xml

The Spring framework supports Servlet 3.0 from version 3.1. You can declare Servlet, Filter and Listener in Java-based configuration, and from version 3.2 you can use the
subclass of AbstractAnnotationConfigDispatcherServletInitializer to configure DispatcherServlet, which will create DispatcherServlet and ContextLoaderListener. The real implementation is not You need to use web.xml again. For example, the following code customizes a DispatcherServletInitializer, which inherits AbstractAnnotationConfigDispatcherServletInitializer.

DispatcherServletInitializer respectively implements getRootConfigClasses, getServletConfigClasses and getServletMappings methods. The getRootConfigClasses method returns classes annotated with @Configuration for ContextLoaderListener to create a Spring context to load non-web-related beans. The getServletConfigClasses method returns classes annotated with @Configuration for DispatcherServlet to create a Spring context to load web-related beans. The string array returned by the getServletMappings method is used to tell the DispatcherServlet to handle requests for those urls. Are you familiar with the purpose of these three methods here? In fact, they are the alternatives to DispatcherServlet and ContextLoaderListener configured in web.xml.

The SpringServletContainerInitializer in Spring3.1 implements the ServletContainerInitializer interface, and defines the javax.servlet.ServletContainerInitializer file under the corresponding jar package META-INF/services/ path, and its content is org.springframework.web.SpringServletContainerInitializer.

According to the above analysis of the javax.servlet.ServletContainerInitializer interface, the onStartup method of SpringServletContainerInitializer will be called when the web application starts. Before analyzing the onStartup method, pay attention to the use of the @HandlesTypes annotation on the SpringServletContainerInitializer class. The value of this annotation is WebApplicationInitializer. Therefore, containers that support Servlet3.0+ will automatically scan the implementation classes of the WebApplicationInitializer interface under the classpath when they start, and these The implementation class passes to the first parameter of the onStartup method.

The above code is simply commented, and you can see that onStartup will traverse and execute the onStartup method of the WebApplicationInitializer interface implementation class. Now, let's look back at the AbstractAnnotationConfigDispatcherServletInitializer class structure.

AbstractAnnotationConfigDispatcherServletInitializer inherits from AbstractDispatcherServletInitializer, and AbstractDispatcherServletInitializer inherits from AbstractContextLoaderInitializer, AbstractContextLoaderInitializer implements WebApplicationInitializer interface, so AbstractAnnotationConfigDispatcherServletInitializer The onStartup method of the ializer subclass will be called when the web application starts to create DispatcherServlet and ContextLoaderListener, and then create a Spring context to complete the application initialization operation.

SpringBoot no longer uses web.xml

Since the Spring framework has gradually replaced web.xml with Java Config starting from 3.1, SpringBoot, as a quick and easy scaffold for using the Spring framework, will certainly not continue to use web.xml.

In the code developed based on SpringBoot, you can still continue to use the new @WebServlet, @WebFilter and @WebListener annotations in the javax.servlet.annotation package in the servlet-api to simplify the declaration of Servlets, filters and listeners, but you need Be careful not to forget to use the @ServletComponentScan annotation provided by SpringBoot to enable scanning of these three annotations.

SpringBoot provides ServletRegistrationBean, FilterRegistrationBean and ServletListenerRegistrationBean for dynamic registration of Servlets, filters and listeners, such as the following code.

Although the above code creates three beans, these three beans are only hosted in the Spring context and not registered in the ServletContext. When will they be registered in the ServletContext? Looking at the source code of ServletRegistrationBean, FilterRegistrationBean and ServletListenerRegistrationBean, you will find that they all inherit indirectly from RegistrationBean, and RegistrationBean implements the ServletContextInitializer interface.

Note that RegistrationBean implements the ServletContextInitializer interface, which is an interface provided by SpringBoot. It is not the same as the ServletContainerInitializer interface we mentioned above, so it must not be confused. The ServletContextInitializer interface uses programming to configure the ServletContext of Servlet3.0+. It will not be automatically called when the Servlet container starts, and its life cycle is managed by Spring.

Let's take the version of the code running on Tomcat7+ as an example. When the SpringBoot project code is running, whether it is embedded in Tomcat or deployed as a war to external Tomcat, the code will run to the SpringApplication.run method to create a Spring context loading bean. Do the initialization operation. In this process, a TomcatStarter object will be created, and then the onStartup method in TomcatStarter will be executed. The following is the source code of TomcatStarter.

Through the source code, it is found that TomcatStarter also implements the ServletContainerInitializer interface, but it does not use the same implementation mechanism as SpringServletContainerInitializer, but uses a hard-coded method to directly create a new TomcatStarter. When creating a TomcatStarter object, a ServletContextInitializer array is passed in. This The content in the array is the bean of the ServletContextInitializer interface implementation class searched from the Spring context. That is to say, the beans (myServlet, myFilter and myListener) created by ServletRegistrationBean, FilterRegistrationBean and ServletListenerRegistrationBean above will be injected into this array. In fact, the array There is also a very important bean, dispatcherServlet, which is a bean created by SpringBoot's automatic configuration function through DispatcherServletRegistrationBean.

After the TomcatStarter object is created, its onStartup method will be called back in the next initialization process. You can see in this method that it still executes the onStartup of each ServletContextInitializer interface implementation class, and then registers the Servlet, Filter and Listener to the ServletContext.

Summarize

So far, we have understood how web.xml is replaced, and we have also found that the framework encapsulates more and more things, and the integration level is getting higher and higher. Although the framework is good, if we don’t understand the ins and outs, we can only make it a tool Users, after a long time, we are just tool people, so it is necessary to study why, what and how.

Guess you like

Origin blog.csdn.net/dyuan134/article/details/130242918