我们都知道-Tomcat, 是一个web发布容器, 运行在当前服务器上, 且监听指定端口(也就是IP:Port), 那么一个http请求打进来以后,
是怎样进到服务里并且处理的呢?
1 ContextLoaderListener类
继承了ContextLoader 实现了 ServletContextListener
重点这个监听接口 ServletContextListener
public interface ServletContextListener extends EventListener {
// 当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter 初始化,
// 并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
default void contextInitialized(ServletContextEvent sce) {
}
// 当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器。
default void contextDestroyed(ServletContextEvent sce) {
}
}
2. Servlet
2.01 Servlet配置
web.xml 中的配置, 这里配置的意思就是实例化DispatcherServlet, 并且它的映射路径是/*, 也就是说http请求打进这个服务之后, 就会进入到这个DispatcherServlet.
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
2.02 Servlet源码
public interface Servlet {
// tomcat通过反射创建servlet之后, 调用init方法 传入ServletConfig(包含了服务名称, 上下文, 参数信息)
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
// 核心逻辑 tomcat解析请求 封装相关头以及参数数据
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
// 销毁前调用的方法
void destroy();
}
从上述源码, 我们可以看的出来, 当一个http请求打进tomcat, 会先封装web.xml中的init param以及上下文数据到ServletConfig, 然后 封装请求头以及传入参数到ServletRequest以及响应相关数据封装到ServletResponse, 再执行service方法, 我们可以先猜测就是这个service方法走到了我们的controller层.
2.1 GenericServlet
// GenericServlet主要将ServletConfig提成了全局变量
private transient ServletConfig config;
2.2 HttpServlet
// 我们可以看的出来 HttpServlet主要是将service方法重写, 讲常见的get, post, delete等等请求 进入到对应的doGet, doPost等等里
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{
method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
2.3 HttpServletBean
实现了 EnvironmentCapable, EnvironmentAware接口 这个类主要是加载参数信息以及封装BeanWrapper
@Override
public final void init() throws ServletException {
// 加载web.xml init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
// BeanWrapper设置pvs属性值
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// 子类扩展逻辑
initServletBean();
}
2.4 FrameworkServlet
@Override
protected final void initServletBean() throws ServletException {
...
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
...
}
protected WebApplicationContext initWebApplicationContext() {
// 获取root WebApplicationContext 也就是Spring IOC容器
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
// 定义SpringMVC上下文
WebApplicationContext wac = null;
// 非第一次进入
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
// 刷新容器
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// 在ServletContext中寻找是否有springMVC容器,初次运行是没有的
wac = findWebApplicationContext();
}
if (wac == null) {
// 如下
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// 如果没有收到刷新监听
synchronized (this.onRefreshMonitor) {
onRefresh(wac);
}
}
if (this.publishContext) {
// 缓存起来 方便下次拿上下文
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
Class<?> contextClass = getContextClass();
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
// 实例化一个容器对象
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
// 设置环境信息
wac.setEnvironment(getEnvironment());
// 设置父容器 也就是Spring IOC容器
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
// SpringMVC的配置信息
wac.setConfigLocation(configLocation);
}
// 刷新容器 完成加载
configureAndRefreshWebApplicationContext(wac);
return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
......
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
// 发布容器刷新事件 onRefresh 最终会调到DispatcherServlet的onRefresh
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();
}
2.5 DispatcherServlet源码
/**
* This implementation calls {@link #initStrategies}.
*/
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
// 初始化九大核心组件
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);// 文件解析
initLocaleResolver(context);// 本地解析
initThemeResolver(context);// 主题解析
initHandlerMappings(context);// url映射解析
initHandlerAdapters(context);// 初始化真正调用的方法
initHandlerExceptionResolvers(context);// 异常解析
initRequestToViewNameTranslator(context);
initViewResolvers(context);// 视图解析
initFlashMapManager(context);
}
HttpServlet里面的doGet为例, 如果一个http请求打进这个项目, 那么就会走到processRequest里的doService方法.最终会走到DispatcherServlet的doService.
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 设置web上下文
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());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
try {
// 核心方法
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
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 {
// 如果存在Multipart文件 进行封装multipartRequest
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 根据请求获取handler拦截链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根据请求获取适配器
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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 拦截器逻辑
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 执行业务逻辑 返回视图模型
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);
}
}
}
}
3.1 HandlerMapping-RequestMappingHandlerMapping举例
@Override
@SuppressWarnings("deprecation")
public void afterPropertiesSet() {
// afterPropertiesSet spring生命周期 初始化中
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(useSuffixPatternMatch());
this.config.setTrailingSlashMatch(useTrailingSlashMatch());
this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
this.config.setContentNegotiationManager(getContentNegotiationManager());
super.afterPropertiesSet();
}
super.afterPropertiesSet();—AbstractHandlerMethodMapping
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
initHandlerMethods();
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
// 处理@RequestMapping注解逻辑
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
// 标有@Controller或者@RequestMapping注解的类 往后执行
processCandidateBean -> detectHandlerMethods
protected void detectHandlerMethods(Object handler) {
// 根据name获取bean class
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
// 如果是代理类 获取父类
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 遍历此类所有方法 T就是RequestMappingInfo
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
// RequestMappingInfo包含了requestMapping注解url 和 handler 也就是method方法
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
// 找出可外部调用的方法
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 注册到registry变量 handlerMethod为bean与method的封装类
// this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
getMappingForMethod(method, userType)
@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
3.2 HandlerAdapter-RequestMappingHandlerAdapter举例
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// synchronizeOnSession 需要session同步处理的操作
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 没有session
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 不需要一个session内同步执行
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// 不包含Cache-Control 则对response进行处理 设置过期时间
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
invokeHandlerMethod
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中配置的InitBinder,用于进行参数的绑定
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 获取容器中全局配置的ModelAttribute和当前HandlerMethod所对应的Controller的ModelAttribute
// 保证业务逻辑之前调用
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 整体调用链封装成ServletInvocableHandlerMethod
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// @ModelAttribute方法调用
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 创建一个一步请求AsyncWebRequest
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 线程池 请求 返回以及Interceptors封装到WebAsyncManager
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
// 判断是否有异步结果
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
// 异步结果进行封装
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 调用目标HandlerMethod
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 封装成ModelAndView且返回
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
流程总结:
- SpringMVC默认加载RequestMappingHandlerMapping(还有其他HandlerMapping类)和RequestMappingHandlerAdapter(还有其他HandlerAdapter类), 因为实现了InitializingBean, 在初始化时会调用afterPropertiesSet初始化逻辑, 会遍历所有的bean, 挑选出有@Controller或者@RequestMapping注解的bean, 进行requestMappingInfo封装(主要就是url和handler以及method对应数据)
- Tomcat启动之后, 会去反射创建DispatcherServlet, HttpServletBean实例化后会调用initServletBean, 然后走到FrameworkServlet的initServletBean方法, 之后会刷新容器, 调到DispatcherServlet的onRefresh方法, 注册九大组件.
- 一个Http(get)请求打到该项目后, 会走到HttpServlet的doGet方法, 然后走到DispatcherServlet的doService, 再到doDispatch, 会根据request拿到HandlerExecutionChain执行链, 走真正方法逻辑之前的拦截器, 通过handler拿到适配器执行@InitBinder和@ModelAttribute注解逻辑, 再执行真正自己的逻辑 封装ModelAndView返回, 再执行业务逻辑之后的拦截器. 最后异常执行异常处理逻辑.