参考资料:servlet-3_1-final.pdf(servlet 3.1规范)8.2.4Shared libraries / runtimes pluggability
通过ServletContainerInitializer来实现可插拔性,至少需要servlet 3+.
1.以上的参考资料提到可以通过ServletContainerInitializer实现可插拔性.每个应用在启动时,容器都会创建一个ServletContainerInitializer实例.
2.框架提供在jar包的META-INF/service目录下的javax.servlet.ServletContainerInitializer文件内容就是指向ServletContainerInitializer实现类.
spring mvc提供的这个实现类叫做org.springframework.web.SpringServletContainerInitializer,这个jar的文件名是spring-web-X.X.X.X.jar.
3.这个实现类的HandlesTypes注解用在表示那些感兴趣的类,这些类或者它的超类是由HandlesTypes值指定的,HandlesTypes的应用与metadata-complete的设置无关.
spring mvc的HandlesTypes值只有WebApplicationInitializer.class一个,那么凡是在类路径上的WebApplicationInitializer子类都是感兴趣的类.它们将会传入onStartup方法的第一个参数.下面是org.springframework.web.SpringServletContainerInitializer#onStartup方法
从此方法可看出,在启动应用时,所有有效(这个有效的意思可以看上面的try外层的if)的Initializer都共用同一个ServletContext,一个一个去启动它的onStartup方法.如果要更改initializers顺序,应该可通过@Order注解(数值越低排序越前 )或实现Ordered接口去实现.
基于java-config的spring mvc,我们一般都会继承AbstractAnnotationConfigDispatcherServletInitializer(它当然是WebApplicationInitializer的实现类)来写一个Initializer.这个Initializer最基本的就帮我们注册了DispatcherServlet.
通过ServletContainerInitializer来实现可插拔性,至少需要servlet 3+.
1.以上的参考资料提到可以通过ServletContainerInitializer实现可插拔性.每个应用在启动时,容器都会创建一个ServletContainerInitializer实例.
2.框架提供在jar包的META-INF/service目录下的javax.servlet.ServletContainerInitializer文件内容就是指向ServletContainerInitializer实现类.
spring mvc提供的这个实现类叫做org.springframework.web.SpringServletContainerInitializer,这个jar的文件名是spring-web-X.X.X.X.jar.
3.这个实现类的HandlesTypes注解用在表示那些感兴趣的类,这些类或者它的超类是由HandlesTypes值指定的,HandlesTypes的应用与metadata-complete的设置无关.
spring mvc的HandlesTypes值只有WebApplicationInitializer.class一个,那么凡是在类路径上的WebApplicationInitializer子类都是感兴趣的类.它们将会传入onStartup方法的第一个参数.下面是org.springframework.web.SpringServletContainerInitializer#onStartup方法
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;
}
AnnotationAwareOrderComparator.sort(initializers);
servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
从此方法可看出,在启动应用时,所有有效(这个有效的意思可以看上面的try外层的if)的Initializer都共用同一个ServletContext,一个一个去启动它的onStartup方法.如果要更改initializers顺序,应该可通过@Order注解(数值越低排序越前 )或实现Ordered接口去实现.
基于java-config的spring mvc,我们一般都会继承AbstractAnnotationConfigDispatcherServletInitializer(它当然是WebApplicationInitializer的实现类)来写一个Initializer.这个Initializer最基本的就帮我们注册了DispatcherServlet.
如果容器不支持servlet3+(有些老古董思想,要绕一下路),那么就离不开web.xml,下面替代方案:
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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"
version="2.5">
<display-name>web</display-name>
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext instead of the default XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<!-- Configuration locations must consist of one or more comma- or space-delimited
fully-qualified @Configuration classes. Fully-qualified packages may also be
specified for component-scanning -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.xxx.auth.web.config.AppConfig</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>charsetFilter</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>charsetFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited and fully-qualified @Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.xxx.auth.web.config.MvcConfig</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>
</web-app>
基于javaConfig的springMvc,不是不使用web.xml,而是可以不使用web.xml,应理解web.xml不是必须的(所以那些所谓的零配置,我认为是不准确的),比如session-config,jsp-config,mime-mapping,error-page还是要使用web.xml,可参考servlet-3_1-final.pdf