一、Servlet3.0+的容器启动过程:
(一)、原理级启动模式:
- Servlet3.0+ 的容器启动时,会扫描项目中的所有库的META-INF/services/javax.servlet.ServletContainerInitializer文件的内容
- 在spring-web.jar下有此文件,文件内容:
org.springframework.web.SpringServletContainerInitializer
此类为Spring的实现,是实现了ServletContainerInitializer的子类,类的声明如下:
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {...
- @HandlesTypes指明了此class要处理的目标class是:WebApplicationInitializer.class,即以下方法中的set中的class类型
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
- onStartup方法的处理逻辑如下:
(1)扫描classpath中的WebApplicationInitializer实现类
(2)将其反射生成对象,调用其方法public void onStartup(ServletContext servletCxt)
,并将ServletContext对象传入到其实现方法中。
(3)而onStartup
方法,即为SpringMVC提供给开发者的API部分。 - 一个具体的实现:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
//自定义的配置类,与SpringFramework的结合点
ac.register(AppConfig.class);
//完成一些Bean的自动化装配,但会覆盖@EnableMVC,所以尽量不要使用
// ac.refresh();
//自定义的配置文件,与SpringFramework的结合点(与配置类二选一)
// XmlWebApplicationContext ac = new XmlWebApplicationContext();
//ac.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
以上代码如何添加Filter?
//OpenSessionInViewFilter
OpenSessionInViewFilter hibernateSessionInViewFilter = new OpenSessionInViewFilter();
FilterRegistration.Dynamic filterRegistration = servletContext.addFilter(
"hibernateFilter", hibernateSessionInViewFilter);
filterRegistration.addMappingForUrlPatterns(
EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE), false, "/");
AppConfig.java
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "cn.johnyu.otherweb.controller")
public class AppConfig implements WebMvcConfigurer {
}
(二)、父子容器(Context Hierarchy)的启动模式:
- 需求是什么?
简单应用,只需要由启动一个WebApplicationContext
就可足够了,但如果需要多个WebApplicationContext就难以应付共享bean的需要了,此时可以采用Context Hierarchy的方式:
- 实现手段:
利用一个由Spring提供的WebApplicationInitializer
模板完成此机制。
使用ConfigClass时:
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { App1Config.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/app1/*" };
}
/*
* 注册过滤器,映射路径与DispatcherServlet一致,路径不一致的过滤器需要注册到另外的WebApplicationInitializer中
*/
@Override
protected Filter[] getServletFilters() {
return new Filter[] {
new HiddenHttpMethodFilter(), new CharacterEncodingFilter() };
}
}
}
使用ConfigXML时
public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
@Override
protected WebApplicationContext createServletApplicationContext() {
XmlWebApplicationContext cxt = new XmlWebApplicationContext();
cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
return cxt;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
/*
* 注册过滤器,映射路径与DispatcherServlet一致,路径不一致的过滤器需要注册到另外的WebApplicationInitializer中
*/
@Override
protected Filter[] getServletFilters() {
return new Filter[] {
new HiddenHttpMethodFilter(), new CharacterEncodingFilter() };
}
}
二、经典的Servlet2.X方式
在WEB-INF/web.xml中
<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>