spring中的WebApplicationInitializer

 

XML-based Approach

要配置核心分发控制器Servlet,即DispatcherServlet,传统做法是直接使用xml进行配置,如下代码所示:

 

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

 

Code-based Approach

在Spring3.1开始可以使用Servlet3.0技术,实现代码编写注册核心控制器。

 

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

   @Override
   public void onStartup(ServletContext container) {
//这两行是为了加载springmvc的配置
     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.
 

 

一旦编写以上类,且将其放置在类路径上,则服务器启动时日志会打印如下日志:

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

对于以上内容,dispatch-config.xml还是依赖xml配置,我们还是可以使用AnnotationConfigWebApplicationContext,完全基于@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("/");
   }
}

 

注意:

web.xml与以上方式并不冲突,可以相互并存,甚至可以做到后者硬编码修改web.xml配置,例如使用ServletContext.getServletRegistration(String)。

实现原理分析

在Spring-web项目中有类SpringServletContainerInitializer,它实现了Servlet3.0的ServletContainerInitializer接口,且优先级会高于xml中配置的listener。在SpringServletContainerInitializer中有注解@HandlesTypes(WebApplicationInitializer.class),具体如下:

  1. 因为这个类声明了HandlesTypes,并指定了类型为WebApplicationInitializer.class,在Servlet3.0+中web容器启动时,会扫描类路径下所有的WebApplicationInitializer接口实现类,并提供一个set集合给onStartup方法执行。
  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. 引入spring-web包后,web.xml配置metadata-complete=false,其实默认不配置就是false,并确保运行环境支持servlet3.0+,就可以不需要再用以前的方式,在web.xml中配置listener或servlet了。
  2. WebApplicationInitializer类可以说是SpringWeb的核心初始化器,可用来初始化注册监听器,包括以往的ContextLoadListener。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值