Spring MVC前端控制器及方法映射源码分析
(个人学习笔记,如有错误欢迎指正!!!)
前端控制器(DispatcherServlet)
DispatcherServlet
<FrameworkServlet
<HttpServletBean
<HttpServlet
首先 DispatcherServlet
是一个 Servlet
,所以基本的流程为 init()->service()->destory()
init()
过程是是现在父类 HttpServletBean
中:
public final void init() throws ServletException {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
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();
}
首先是读取 <init-param>
的配置元素,配置相关的bean,之后调用 initServletBean()
方法来创建Servlet WebApplicationContext
。 initServletBean()
被子类 FrameworkServlet
重写了:
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
if (logger.isInfoEnabled()) {
logger.info("Initializing Servlet '" + getServletName() + "'");
}
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
if (logger.isDebugEnabled()) {
String value = this.enableLoggingRequestDetails ?
"shown which may lead to unsafe logging of potentially sensitive data" :
"masked to prevent unsafe logging of potentially sensitive data";
logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
"': request parameters and headers will be " + value);
}
if (logger.isInfoEnabled()) {
logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
}
}
主要的作用就是创建一个 WebApplicationContext
, initFrameworkServlet()
的实现为空。
DispatcherServlet
在相应请求时,调用的时父类 FrameworkServlet
的 service()
方法:
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
该方法主要是判断请求方法是否为 patch
或者为 null
,如果是则调用 processRequest(request, response)
,否则调用父类 HttpServlet
中的 service()
方法,该方法会根据请求类型调用相应的 doGet
,doPost
等方法,FrameworkServlet
重写了这些方法,最终均会调用 processRequest(request, response)
方法。
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
在 processRequest(request, response)
方法中,先将获取到的相关信息通过 initContextHolders
方法绑定到线程上,再调用 doService()
方法(该方法由 DispatcherServlet
实现),最后调用 resetContextHolders
方法解除相关信息与线程的绑定。
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
......
initContextHolders(request, localeContext, requestAttributes);
try {
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
......
}
doService()
方法中主要调用 doDispatch()
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
......
try {
doDispatch(request, response);
}
finally {
......
}
首先判断是否为 Multipart
请求类型,如果是便通过 multipartResolver
来解析请求
通过getHandler
方法找到从HandlerMapping
找到该请求对应的handler
,如果没有找到对应的handler
则抛出异常。
通过getHandlerAdapter
方法找到handler
对应的HandlerAdapter
如果有拦截器,执行拦截器preHandler
方法
HandlerAdapter
执行handle
方法处理请求,返回ModelAndView
。
如果有拦截器,执行拦截器postHandle
方法
然后调用processDispatchResult
方法处理请求结果,封装到response
中。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
......
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == 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 (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) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
......
}
HandlerMapping 映射处理
RequestMappingHandlerMapping
是Spring MVC中的内置Bean,会自动进行加载,同时该类还实现了 InitializingBean
接口,该接口提供了 afterPropertiesSet()
方法,该方法会在bean初始化的时候执行,
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
该方法是在 AbstractAutowireCapableBeanFactory.invokeInitMethods()
方法中调用,该方法会在初始化bean的时候调用,该方法首先判断这个bean是不是 InitializingBean
接口的实例,如果是便调用 afterPropertiesSet()
方法。
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
RequestMappingHandlerMapping -> RequestMappingInfoHandlerMapping -> AbstractHandlerMethodMapping -> InitializingBean
afterPropertiesSet()
实现在 AbstractHandlerMethodMapping
类中,在该方法中,首先遍历所有的bean,然后调用 isHandler()
方法判断是否为controller,最后调用 detectHandlerMethods()
方法遍历类中所有的方法。
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
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);
}
}
isHandler()
方法实现在 RequestMappingHandlerMapping
中,通过判断类是否有 @Controller
和 @RequestMapping
注解来判断该类是不是能够由RequestMappingHandlerMapping
处理。
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
下面的方法是遍历controller类中的方法,并且使用 registerHandlerMethod()
方法进行注册。
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
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);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
Spring MVC 项目加载的所有内置bean:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#1
org.springframework.web.servlet.handler.MappedInterceptor#0
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
org.springframework.web.servlet.view.InternalResourceViewResolver#0
org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
org.springframework.web.socket.server.support.WebSocketHandlerMapping#0
org.springframework.web.socket.server.support.DefaultHandshakeHandler#0
org.springframework.web.socket.server.support.WebSocketHttpRequestHandler#0
org.springframework.web.socket.server.support.WebSocketHandlerMapping#1
org.springframework.web.socket.server.support.DefaultHandshakeHandler#1
org.springframework.web.socket.server.support.WebSocketHttpRequestHandler#1
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
org.springframework.format.support.FormattingConversionServiceFactoryBean#0
org.springframework.data.redis.listener.RedisMessageListenerContainer#0
org.springframework.remoting.rmi.RmiServiceExporter#0
org.springframework.web.socket.config.annotation.DelegatingWebSocketConfiguration
HandlerMapping 路由匹配
DispatcherServlet
接受到request请求之后,遍历所有的 HandlerMapping,并且调用 HandlerMapping.getHandler()
方法,该方法实现在父类 AbstractHandlerMapping
中,在该方法中,首先根据请求获取相应的处理方法(getHandlerInternal()
),然后调用 getHandlerExecutionChain()
获得执行链。
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 = obtainApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
getHandlerInternal()
实现在 AbstractHandlerMethodMapping
中,该方法通过 lookupHandlerMethod()
方法获得操作方法。
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
lookupHandlerMethod()
方法如下,首先根据路径查找匹配的方法,如果结果为空,就将所有的方法全部加到list中(精确匹配优于模糊匹配),然后根据特别的规则对list中的方法进行排序(优先匹配),找到优先级最高的两个,如果这两个相同,表示冲突并抛出异常,否则返回最好的方法。
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}