Servlet 初始化介绍
1、3.0 以前版本
Web 容器读取配置在web.xml 的 servlet ,filter。并且执行servlet,filter 的初始化 ,。从初始化中可以获取servletContext 。从而获取相关的配置信息
web.xml 配置样例
HelloWorldFilter
/hello
HelloWorldServlet
/hello
2、3.0 以后版本
servlet 提供了 ServletContainerInitializer#onStartup 接口,web 容器通过SPI 找到实现的 ServletContainerInitializer 接口 ,执行web容器初始化配置。
SPI.png
@HandlesTypes 注解,Servlet 3.0+ 会自动scan 实现handler WebApplicationInitializer 接口的所有类
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List initializers = new LinkedList<>();
for (Class waiClass : webAppInitializerClasses) {
initializers.add(ReflectionUtils.accessibleConstructor(waiClass).newInstance());}
}
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
Spring 与Servlet集成
核心类图
Servlet.png
FrameworkServlet
initServletBean,创建和初始化WebApplicationContext,由容器调用
protected final void initServletBean() throws ServletException {
this.webApplicationContext =createWebApplicationContext();
initFrameworkServlet();
}
createWebApplicationContext : 配置了Context 类就使用配置的类,默认使用XmlWebApplicationContext 。
private WebApplicationContext createWebApplicationContext() throws ServletException {
ServletContext sc = getServletConfig().getServletContext();
WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(sc);
String namespace = getNamespace();
WebApplicationContext waca = (this.contextClass != null) ?
instantiateCustomWebApplicationContext(this.contextClass, parent, namespace) :
new XmlWebApplicationContext(parent, namespace);
waca.setServletContext(sc);
return waca;
}
DispatcherServlet
1、initFrameworkServle,来自于FrameworkServlet 的模板方法,由父类调用
protected void initFrameworkServlet() throws ServletException {
initLocaleResolver();
initThemeResolver();
initHandlerMappings();
initHandlerAdapters();
initViewResolver();
}
所有init方法 中获取的对象 从spring 容器获取, 这是创建context 之后的获取,bean 实例已经在context 中先生成好的。
this.localeResolver = (LocaleResolver) getWebApplicationContext().getBean(LOCALE_RESOLVER_BEAN_NAME);
this.themeResolver = (ThemeResolver) getWebApplicationContext().getBean(THEME_RESOLVER_BEAN_NAME);
HandlerMapping hm = (HandlerMapping) getWebApplicationContext().getBean(beanName);
String[] handlers = getWebApplicationContext().getBeanDefinitionNames(HandlerAdapter.class);
this.viewResolver = (ViewResolver) getWebApplicationContext().getBean(VIEW_RESOLVER_BEAN_NAME);
2、doService,提供servlet 核心服务
protected void doService(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// request 设置属性
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
// 查找匹配的HandlerExecutionChain
HandlerExecutionChain mappedHandler = getHandler(request);
// 前置拦截,后续版本中拦击器功能有所加强
if (mappedHandler.getInterceptors() != null) {
for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {
HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
if (!interceptor.preHandle(request, response, mappedHandler.getHandler())) {
return;
}
}
}
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理请求
ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
//渲染页面响应客户端
if (mv != null) {
logger.debug("Will render model in DispatcherServlet with name '" + getServletName() + "'");
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
render(mv, request, response, locale);
}
}
XmlWebApplicationContext
核心类图
WebApplicationContext.png
1、setServletContext ,servlet 初始化调用
public void setServletContext(ServletContext servletContext) throws ApplicationContextException {
this.servletContext = servletContext;
// 从servletContext 获取配置文件位置
this.configLocation = getConfigLocationForNamespace();
// 执行AbstractApplicationContext 方法
refresh();
if (this.namespace == null) {
WebApplicationContextUtils.publishConfigObjects(this); WebApplicationContextUtils.publishWebApplicationContext(this);
}
}
2、从servletContext 获取配置文件位置
protected String getConfigLocationForNamespace() {
if (getNamespace() != null) {
String configLocationPrefix = this.servletContext.getInitParameter(CONFIG_LOCATION_PREFIX_PARAM);
String prefix = (configLocationPrefix != null) ? configLocationPrefix : DEFAULT_CONFIG_LOCATION_PREFIX;
String configLocationSuffix = this.servletContext.getInitParameter(CONFIG_LOCATION_SUFFIX_PARAM);
String suffix = (configLocationSuffix != null) ? configLocationSuffix : DEFAULT_CONFIG_LOCATION_SUFFIX;
return prefix + getNamespace() + suffix;
}
else {
String configLocation = this.servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
return (configLocation != null) ? configLocation : DEFAULT_CONFIG_LOCATION;
}
}
Spring 专题