初始化DispatcherServlet会建立自己的IoC容器并从ServletContext中获取根上下文作为自己上下文的双亲上下文.然后对自己的上下文初始化,保存到ServletContext中去
继承关系如此
主要搞事的方法是初始化initServletBean()和接收请求doGet()/doPost()
当Servlet初始化时会调用init()方法.HttpServletBean的init()
public final void init() throws ServletException {
// Let subclasses do whatever initialization they like.
initServletBean();
}
子类FrameworkServlet的实现
protected final void initServletBean() throws ServletException {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
protected WebApplicationContext initWebApplicationContext() {
if (wac == null) {
//创建MVC上下文
wac = createWebApplicationContext(rootContext);
}
... return wac;
}
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
return createWebApplicationContext((ApplicationContext) parent);
}
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
Class<?> contextClass = getContextClass();
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
wac.setConfigLocation(getContextConfigLocation());
configureAndRefreshWebApplicationContext(wac);
return wac;
}
默认是XmlWebApplicationContext protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
wac.setId(this.contextId);
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
wac.refresh();
}
最后一个方法就是配置并refresh()上下文了.熟悉的剧情啊.于是就得到了这个MVC上下文.在创建MVC的上下文之后
protected WebApplicationContext initWebApplicationContext() {
if (wac == null) {
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
onRefresh(wac);
}
}
在这个onRefresh()里面有一些骚操作了.具体实现在DispatcherServlet中了
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);//文件上传解析器
initLocaleResolver(context);//区域解析器
initThemeResolver(context);//主题
initHandlerMappings(context);//URL映射
initHandlerAdapters(context);//处理适配
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);//视图
initFlashMapManager(context);
}
初始化了很多的东西.这些东西呢,可以在org\springframework\web\servlet\DispatcherServlet.properties这个文件内看到对应的默认实现类
看一下关于url映射,获取到handlerMapping之后赋值到this.handlerMapping上了.
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
如何处理Http请求了,从url到对应的Controller
HandlerMapping及其实现类,就这四种HandlerMapping了.
RequestMappingHandlerMapping是使用@RquestMapping注解时的实现
看一个最简单的SimpleUrlHandlerMapping
public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
private final Map<String, Object> urlMap = new LinkedHashMap<String, Object>();
public void setMappings(Properties mappings) {
CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
}
public void setUrlMap(Map<String, ?> urlMap) {
this.urlMap.putAll(urlMap);
}
public Map<String, ?> getUrlMap() {
return this.urlMap;
}
@Override
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
registerHandlers(this.urlMap);
}
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
}
else {
for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
String url = entry.getKey();
Object handler = entry.getValue();
if (!url.startsWith("/")) {
url = "/" + url;
}
if (handler instanceof String) {
handler = ((String) handler).trim();
}
registerHandler(url, handler);
}
}
}
}
没啥内容.一个存放URL和对应控制器Map和一个注册方法,方法具体实现在基类中.这里的initApplicationContext()在一个bean的postProcessor中调用.这个bean是org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
从Map中获取对应控制器方法在接口中定义
public interface HandlerMapping {
/**
* Return a handler and any interceptors for this request. The choice may be made
* on request URL, session state, or any factor the implementing class chooses.
* <p>The returned HandlerExecutionChain contains a handler Object, rather than
* even a tag interface, so that handlers are not constrained in any way.
* For example, a HandlerAdapter could be written to allow another framework's
* handler objects to be used.
* <p>Returns {@code null} if no match was found. This is not an error.
* The DispatcherServlet will query all registered HandlerMapping beans to find
* a match, and only decide there is an error if none can find a handler.
* @param request current HTTP request
* @return a HandlerExecutionChain instance containing handler object and
* any interceptors, or {@code null} if no mapping found
* @throws Exception if there is an internal error
*/
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
这个方法的返回之物是这样的public class HandlerExecutionChain {
private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
public HandlerExecutionChain(Object handler) {
this(handler, (HandlerInterceptor[]) null);
}
public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) {
this.handler = handler;
this.interceptors = interceptors;
}
}
主要是持有Interceptor链和handler.Interceptor器链不是这个SimpleUrlHandlerMapping用的,是别的什么RequestMapingHandlerMapping用的,先不关心.回到上面的SimpleUrlHandlerMapping看注册方法的具体实现基类AbstractUrlHandlerMapping
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Object resolvedHandler = handler;
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
if (getApplicationContext().isSingleton(handlerName)) {
resolvedHandler = getApplicationContext().getBean(handlerName);
}
}
Object mappedHandler = this.handlerMap.get(urlPath);
if (urlPath.equals("/")) {
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
setDefaultHandler(resolvedHandler);
}
else {
this.handlerMap.put(urlPath, resolvedHandler);
}
}
简简单单的判断获取放置到Map<String,Object> handlerMap中去了
然后看getHandler()的具体实现,在基类AbstractHandlerMapping中
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
获取handler和interceptor,实例化HandlerExecutionChian
获取handler的具体实现在AbstractUrlHandlerMapping
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = getApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
return handler;
}
从request中获取url,找到对应handler
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// Direct match?
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
// Pattern match?
List<String> matchingPatterns = new ArrayList<String>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern +"/");
}
}
}
String bestPatternMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
Collections.sort(matchingPatterns, patternComparator);
bestPatternMatch = matchingPatterns.get(0);
}
if (bestPatternMatch != null) {
handler = this.handlerMap.get(bestPatternMatch);
if (handler == null) {
Assert.isTrue(bestPatternMatch.endsWith("/"));
handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
}
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
}
return null;
}
这样我们就可以从url映射Controller了.
如何从Http请求到hander呢.
Servlet的doService()这是Http的入口.
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
doDispatch(request, response);
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);//1
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);//2
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
首先看如何getHandler(),这里已经去掉了第二个参数isCache,直接自身持有这个handlerMapping,然后直接getHandler()调用到了基类AbstractHandlerMapping的方法了.
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
获取的handler是否是符合指定规范的对象,调用
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (ha.supports(handler)) {
return ha;
}
}
}
有几种实现,一种是
public class SimpleServletHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Servlet);
}
是否是Servlet,还有这样的
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
回到doDispatcher中看这一句,说得很明白了
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
这样获取到了ModelAndView然后
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
render(mv, request, response);
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
View view;
if (mv.isReference()) {
// We need to resolve the view name.
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
}
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
获取视图对象,然后渲染
从视图名称获取视图对象,尝试获取视图对象
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
HttpServletRequest request) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}
public View resolveViewName(String viewName, Locale locale) throws BeansException {
ApplicationContext context = getApplicationContext();
if (!context.containsBean(viewName)) {
return null;
}
if (!context.isTypeMatch(viewName, View.class)) {
return null;
}
return context.getBean(viewName, View.class);
}
render()是定义在顶级接口中的,看下继承关系
看下JstlView这个是用来处理JSP页面里面带有jstl标签的,里面render()方法在基类AbstractView里
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
" and static attributes " + this.staticAttributes);
}
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
protected Map<String, Object> createMergedOutputModel(Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) {
Map<String, Object> mergedModel = new LinkedHashMap<String, Object>(size);
mergedModel.putAll(this.staticAttributes);
mergedModel.putAll(pathVars);
mergedModel.putAll(model);
mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));
return mergedModel;
}
就是往Map塞了一些信息然后就交给renderMergedOutputModel(),这个方法的实现当然是选择基类InternalResourceView了
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Expose the model object as request attributes.
exposeModelAsRequestAttributes(model, request);
exposeHelpers(request);//JSTL相关操作
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
// If already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {//如果include过,或者已提交
response.setContentType(getContentType());
rd.include(request, response);
}else {//转发
rd.forward(request, response);
}
}
将一些模型数据塞到rquest中去 protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {
for (Map.Entry<String, Object> entry : model.entrySet()) {
String modelName = entry.getKey();
Object modelValue = entry.getValue();
if (modelValue != null) {
request.setAttribute(modelName, modelValue);
}
else {
request.removeAttribute(modelName);
}
}
}
处理一些JSTL相关,实现在JstlView
protected void exposeHelpers(HttpServletRequest request) throws Exception {
if (this.messageSource != null) {
JstlUtils.exposeLocalizationContext(request, this.messageSource);
}
else {
JstlUtils.exposeLocalizationContext(new RequestContext(request, getServletContext()));
}
}
这些操作之后需要获取转发的路径prepareForRendering() protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response)
throws Exception {
String path = getUrl();
return path;
}
public String getUrl() {
return this.url;
}
这样就将转发到了指定的url上渲染了