方式一、编写web.xml
通常我们将一个spring mvc程序部署到Servlet容器(例如Tomcat)时,会使用该方式,示例如下:
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
其中,配置文件路径如图:
关于web.xml方式的更多细节不再探讨
方式二、实现WebApplicationInitializer(需要容器实现了Servlet 3.0+)
示例:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(javax.servlet.ServletContext servletContext) throws ServletException {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
ac.register(SpringContent.class);
ac.refresh();
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletContext.addServlet("mvc", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}
注:以上代码参考了spring官方文档:DispatcherServlet
其中,SpringContent类如下:
@ComponentScan(basePackages = "controller")
@Configuration
public class SpringContent {
@Bean
public org.springframework.web.servlet.view.InternalResourceViewResolver internalResourceViewResolver(){
return new org.springframework.web.servlet.view.InternalResourceViewResolver("/WEB-INF/views/", ".jsp");
}
}
实现WebApplicationInitializer的方式不再需要编写web.xml,实现了WebApplicationInitializer的具体类的onStartup函数会在Servlet容器启动时自动被调用,从而实现了在方法内注册spring ioc容器以及DispatcherServlet。
实现WebApplicationInitializer方式的原理如下
1.Servlet 3.0中定义了一个SPI接口javax.servlet.ServletContainerInitializer:
关于SPI是什么,可参考:java中的SPI机制
2.然后spring mvc有一个这个接口的实现类:org.springframework.web.SpringServletContainerInitializer
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
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)
ReflectionUtils.accessibleConstructor(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);
}
}
}
其中@HandlesTypes(WebApplicationInitializer.class),Servlet容器会查找所有jar包里实现了WebApplicationInitializer的类,最终会找到我们编写的MyWebApplicationInitializer并调用其onStartup方法。