1、DispatchServlet
前端控制器,请求处理逻辑的实现
2、HandlerMapping
处理器映射,为mvc中url路径与Controller对象的映射,DispatcherServlet就是基于此组件来寻找对应的Control。 目前主流的三种mapping: BeanNameUrlHandlerMapping,基于ioc中beanName以 "/" 开头的Bean的映射
SimpleUrlHandlerMapping,基于手动配置 url 与controller映射
RequestMappingHandlerMapping,基于@RequestMapping注解配置对应的映射
annotation-driven默认添加的三种handler
3、HandlerAdapter
Springmvc 采用适配器模式来适配调用指定Handler,根据Handler的不同种类采用不同的。
Controller对应适配器SimpleControllerHandlerAdapter,标准控制器,返回ModelAndView
HttpRequestHandler对应适配器HttpRequestHandlerAdapter,业务自行处理 请求,不需要通过modelAndView转到视图
Servlet对应适配器SimpleServletHandlerAdapter,基于标准的servlet处理
HandlerMethod对应适配器RequestMappingHandlerAdapter,基于@RequestMapping对应方法处理
4、HandlerExecutionChain
处理器执行链
5、ViewResolver
视图解析器,找到应的Adapter 之后就会基于适配器调用业务处理,处理完之后业务方会返回一个 ModelAndView ,在去查找对应的视图进行处理。
6、View
具体解析视图, 获取对应View来解析生成Html并返回
7、HandlerExceptionResolver
处理器异常解析器,用于指示当出现异常时 Spring mvc 该如何处理
8、HandlerInterceptor
处理器拦截器
web服务器启动tomcat首先会去加载web.xml配置文件
dispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring-mvc.xml
1
首先就实例化DispatcherServlet,在这里还配置了监听tomcat容器启动来初始化spring容器,ContextLoaderListener是spring框架中对ServletContextListener的一个实现,ServletContextListener依赖于sevlet容器,那么在tomcat启动的时候会调用contextInitialized方法来初始化。
另外如果没有配置ContextLoaderListener,在DispatcherServlet的父类FrameworkServlet会去初始化spring容器。
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
//如果没有配置ContextLoaderListener加载容器,那么servlet也会加载容器
wac = createWebApplicationContext(rootContext);
}
在createWebApplicationContext会调用configureAndRefreshWebApplicationContext初始化容器,后面就是调用spring容器初始化代码。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
if (this.contextId != null) {
wac.setId(this.contextId);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
}
}
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
//初始化容器
wac.refresh();
}
spring容器启动就会去加载相应的配置文件,创建bean。
component-scan在这里不在讲,我们现在主要看
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}
}
我们来看AnnotationDrivenBeanDefinitionParser类的parse方法,在这里面会注册很多相应的spring自带的bean,比如RequestMappingHandlerMapping。
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
........
MvcNamespaceUtils.registerDefaultComponents(context, source);
可以看到已经把RequestMappingHandlerMapping注册到容器了,还有一些默认的组件
public static void registerDefaultComponents(ParserContext parserContext, @Nullable Object source) {
registerBeanNameUrlHandlerMapping(parserContext, source);
registerHttpRequestHandlerAdapter(parserContext, source);
registerSimpleControllerHandlerAdapter(parserContext, source);
registerHandlerMappingIntrospector(parserContext, source);
}
RequestMappingHandlerMapping是实现了InitialzingBean接口的,而这个类的父类AbstractHandlerMethodMapping的afterPropertiesSet方法是整个映射关系建立的入口
public void afterPropertiesSet() {
//建立映射关系
initHandlerMethods();
int total = this.getHandlerMethods().size();
if ((logger.isTraceEnabled() && total == 0) || (logger.isDebugEnabled() && total > 0) ) {
logger.debug(total + " mappings in " + formatMappingName());
}
}
而initHandlerMethods是主要实现映射关系的方法
protected void initHandlerMethods() {
String[] beanNames = obtainApplicationContext().getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
查找Controller下所有带有@RequestMapping注解的方法,最后注册HandlerMethod
protected void detectHandlerMethods(final Object handler) {
Class> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
final Class> userType = ClassUtils.getUserClass(handlerType);
Map methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup) method -> getMappingForMethod(method, userType));
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
methods.forEach((key, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(key, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
查找所有带@RequestMapping的方法,并存放到Map
我们知道当一个请求来是,会执行servlet的doService方法,doService()中的核心逻辑由doDispatch()实现
doDispatch(request, response);
主要看doDispatch方法
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);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 返回 HandlerExecutionChain 执行链 (Handler HandlerInterceptors )
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 返回handler对应的适配器
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)) {
// 实现LastModified接口的getLastModified方法,返回一个时间戳,请求中会增加If-Modified-Since参数
// 通过checkNotModified比较两次请求时间戳,如果一致,就直接返回 http响应头,
// 静态资源取浏览器缓存,status code 变为304
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
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());
//用于管理异步请求处理的中心类,主要用作SPI,通常不直接由应用程序类使用。
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);
}
// 将modelAndView交给视图解析器处理
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);
}
}
}
}
在方法内mappedHandler = this.getHandler(processedRequest)就是根据当前的请求去拿一个Handler,这个Handler就是我们写的控制器(controller),也就是去HandlerMapping集合遍历寻找。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
接下来我们通过HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler())就是去拿相应的适配器类,前面有对照过。拿到控制器适配器中执行控制器。
接下来就是执行拦截器的逻辑了
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 调用业务逻辑
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//用于管理异步请求处理的中心类,主要用作SPI,通常不直接由应用程序类使用。
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
//拦截器后置方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
如果你有ModelAndView,就返回一个ModelAndView.然后返回给试图对象,然后把视图对象交给视图解析器,去渲染,最后响应给用户。
将modelAndView交给视图解析器处理
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)
先会判断是否有异常,有异常会进入异常处理机制,如果没有就会去渲染视图
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
// 异常判断
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
//异常处理机制,处理完成之后返回errorView 跳转到异常视图
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
//渲染视图
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
// 调用拦截器 afterCompletion 方法
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}