spring mvc基于编码配置的原理

使用spring mvc的时候需要注册DispatcherServletDispatcherServlet是一个前端控制器,主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端。我们配置DispatcherServlet最典型的是使用web.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/spring-mvc.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>

   

spring3.1引入了WebApplicationInitializer接口,有了它,我们不需要配置web.xml初始化web应用,只需要继承该接口,通过编码实现相应的配置:

public class Initializer implements WebApplicationInitializer {

@Override

 public void onStartup(ServletContext servletContext) throws ServletException {

 AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();

  ctx.register(WebAppConfig.class);

  servletContext.addListener(new ContextLoaderListener(ctx));

  ctx.setServletContext(servletContext);

  Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));

  servlet.addMapping("/");

  servlet.setLoadOnStartup(1);

 

}

}

 

那通过编码方式有什么好处呢?它可以充分利用编译器,在编译期间检查出配置中的错误,另外,这增强了配置的灵活性和可控性,你可以在启动过程中自定义需要的检查验证条件。

 

Spring mvc是跟着更底层的接口标准servlet走的,servlet3+以后引入ServletContainerInitializer接口,这为去web.xml,基于代码配置提供了一种途径:

 

public interface ServletContainerInitializer {

 

 public void onStartup(Set<Class<?>> c, ServletContext ctx)

     throws ServletException;

}

 

SpringSpringServletContainerInitializer 类实现了该接口:

 

//HandlesTypes注解标识SpringServletContainerInitializer 类启动时需要处理的类,此处专门标识了WebApplicationInitializer,正如前面所展示的,我们正是通过实现WebApplicationInitializer接口.来作一些配置工作的。

 

@HandlesTypes(WebApplicationInitializer.class)

public class SpringServletContainerInitializer implements ServletContainerInitializer {

 public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {

 

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

 //以下代码对前面我们实现的WebApplicationInitializer作了循环,实例化,调用onStartUp 等   操作。

  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;

  }

 

  Collections.sort(initializers, new AnnotationAwareOrderComparator());

  servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);

 

  for (WebApplicationInitializer initializer : initializers) {

   initializer.onStartup(servletContext);

  }

 }

 

}  

 

tomcat7以后采用了servlet3标准,我们启动tomcat7servlet3容器)时,容器通过JAR Services API 机制,探测到spring-web包下的一个文件META-INF/services/javax.servlet.ServletContainerInitializer,文件内声明实现类,进而调用其onStartup方法,如果以后我们要自己实现ServletContainerInitializer ,也需要在相应jar包的 META-INF/services目录下放置这样一个以接口的全限定名命名的文件。

spring mvc基于编码配置的原理

 

程序员局限于框架的使用,将始终停留于浅层次的水平,只有深入框架,理解原理,甚至阅读优化其中的源码,才是升级打怪的王道,大家有空可以去看看源码,我们随时讨论。