WebApplicationInitializer in spring4

XML-based Approach

To configure the core distribution controller servlet, that is, the DispatcherServlet, the traditional way is to configure it directly using xml, as shown in the following code:

<servlet>
  <servlet-name>dispatcher</servlet-name>
  <servlet-class>
    org.springframework.web.servlet.DispatcherServlet
  </servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/dispatcher-config.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

Code-based Approach

Starting from Spring 3.1, Servlet 3.0 technology can be used to implement code writing and registering core controllers.

@Order(100)//指定加载顺序,不指定默认为最小,即最先执行,或者实现Ordered 接口也行
public class MyWebAppInitializer implements WebApplicationInitializer {

   @Override
   public void onStartup(ServletContext container) {
     XmlWebApplicationContext appContext = new XmlWebApplicationContext();
     appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");

     ServletRegistration.Dynamic dispatcher =
       container.addServlet("dispatcher", new DispatcherServlet(appContext));
     dispatcher.setLoadOnStartup(1);
     dispatcher.addMapping("/");
   }

}
//其实也可以使用继承完成以上功能org.springframework.web.servlet.support.AbstractDispatcherServletInitializer.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

Once the above class is written and placed on the classpath, the log will print the following log when the server starts:

2017-03-01 23:33:05.529:INFO:/:main: 2 Spring WebApplicationInitializers detected on classpath
  • 1

For the above content, dispatch-config.xml still depends on xml configuration, we can still use AnnotationConfigWebApplicationContext, which is completely based on @Configuration.

public class MyWebAppInitializer implements WebApplicationInitializer {

    @Override
 public void onStartup(ServletContext container) {
     // Create the 'root' Spring application context
     AnnotationConfigWebApplicationContext rootContext =
       new AnnotationConfigWebApplicationContext();
     rootContext.register(AppConfig.class);

     // Manage the lifecycle of the root application context
     container.addListener(new ContextLoaderListener(rootContext));

     // Create the dispatcher servlet's Spring application context
     AnnotationConfigWebApplicationContext dispatcherContext =
       new AnnotationConfigWebApplicationContext();
     dispatcherContext.register(DispatcherConfig.class);

     // Register and map the dispatcher servlet
     ServletRegistration.Dynamic dispatcher =
       container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
     dispatcher.setLoadOnStartup(1);
     dispatcher.addMapping("/");
   }

}
  • 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

Notice:

web.xml does not conflict with the above methods, and can coexist with each other, and even the latter can be hard-coded to modify the web.xml configuration, such as using ServletContext.getServletRegistration(String).

Implementation principle analysis

There is a class SpringServletContainerInitializer in the Spring-web project, which implements the ServletContainerInitializer interface of Servlet3.0, and has a higher priority than the listener configured in xml. There is an annotation @HandlesTypes(WebApplicationInitializer.class) in SpringServletContainerInitializer, as follows:

  1. Because this class declares HandlesTypes and specifies the type as WebApplicationInitializer.class, when the web container starts in Servlet3.0+, it will scan all the WebApplicationInitializer interface implementation classes in the classpath, and provide a set collection for the onStartup method to execute.
  2. onStartup方法执行时,会遍历该set,并使用newInstance()方式进行实例化,实例化后依据@Order注解进行排序,最后在依次调用onStartup(ServletContext)方法,完成初始化。
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
    throws ServletException {

  List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();

  if (webAppInitializerClasses != null) {
    for (Class<?> waiClass : webAppInitializerClasses) {
      // Be defensive: Some servlet containers provide us with invalid classes,
      // no matter what @HandlesTypes says...
      if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
          WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
        try {
          initializers.add((WebApplicationInitializer) waiClass.newInstance());
        }
        catch (Throwable ex) {
          throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
        }
      }
    }
  }

  if (initializers.isEmpty()) {
    servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
    return;
  }

  servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
  AnnotationAwareOrderComparator.sort(initializers);
  for (WebApplicationInitializer initializer : initializers) {
    initializer.onStartup(servletContext);
  }
}
  • 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

总结:

  1. 引入spring-web包后,web.xml配置metadata-complete=false,其实默认不配置就是false,并确保运行环境支持servlet3.0+,就可以不需要再用以前的方式,在web.xml中配置listener或servlet了。
  2. WebApplicationInitializer类可以说是SpringWeb的核心初始化器,可用来初始化注册监听器,包括以往的ContextLoadListener。

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326445667&siteId=291194637