RequestMapping 原理
- spring-webmvc-4.3.7.RELEASE
SpringMVC 启动的时候,会加载 加了注解 @Controller 的 Bean.
栗子:
代码语言:javascript复制@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = {"/show"})
public String testTest() {
return "/jsp/index";
}
}
- @Controller 注解, 它标记的类就是一个 SpringMVC Controller对象,分发处理器会扫描使用该注解的类的方法,并检测该方法是否使用了@RequestMapping注解。
- @RequestMapping注解用来把web请求映射到相应的处理函数。
@Controller和@RequestMapping结合起来完成了Spring MVC请求的派发流程。
@RequestMapping 处理流程
- 注册RequestMappingHandlerMapping bean.
- 实例化 RequestMappingHandlerMapping bean.
- 获取 RequestMappingHandlerMaping bean 实例.
- 接收 Request 请求
- 在 RequestMappingHandlerMapping 实例中查找对应的 Handler
- handler 处理请求。
RequestMappingHandlerMapping 是如何实例化的
简述:new 出来的,带有父类 AbstractHandlerMethodMapping 属性 mappingRegistry , mappingRegistry key value 中的 value 指的是 带有 requestMapping 注解的方法 。
如果想要 RequestMapping 注解生效,必须在 xml 文件中配置,< mvc:annotation-driven/>。
配置完 xml 之后 ,下一步解析 bean。
代码语言:javascript复制protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//如果该元素属于默认命名空间走此逻辑。Spring的默认namespace为:http://www.springframework.org/schema/beans“
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i ) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
//对document中的每个元素都判断其所属命名空间,然后走相应的解析逻辑
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
//如果该元素属于自定义namespace走此逻辑 ,比如AOP,MVC等。
delegate.parseCustomElement(root);
}
}
beans 等默认命名空间执行 parseDefaultElement() 方法,其他命名空间执行 parseCustomElement() 方法.
代码语言:javascript复制 public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
进入parseCustomElement(ele, null)方法。
代码语言:javascript复制public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
//获取该元素namespace url
String namespaceUri = getNamespaceURI(ele);
//得到NamespaceHandlerSupport实现类解析元素
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" namespaceUri "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
进入NamespaceHandlerSupport类的parse()方法。
代码语言:javascript复制 public BeanDefinition parse(Element element, ParserContext parserContext) {
//此处得到AnnotationDrivenBeanDefinitionParser类来解析该元素
return findParserForElement(element, parserContext).parse(element, parserContext);
}
- 获取元素的解析类
- 解析元素
获取解析类
代码语言:javascript复制private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
String localName = parserContext.getDelegate().getLocalName(element);
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" localName "]", element);
}
return parser;
}
解析< mvc:annotation-driven/>元素 进入AnnotationDrivenBeanDefinitionParser类的parse()方法。
注解解析器处理
代码语言:javascript复制public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
XmlReaderContext readerContext = parserContext.getReaderContext();
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);
RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);
//生成RequestMappingHandlerMapping bean信息
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add("order", 0);
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
......
//此处HANDLER_MAPPING_BEAN_NAME值为:RequestMappingHandlerMapping类名
//容器中注册name为RequestMappingHandlerMapping类名
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
......
}
Spring 容器中注册了一个名为 “HANDLER_MAPPING_BEAN_NAME”,类型为 RequestMappingHandlerMapping.
RequestMappingHandlerMapping 实例化
RequestMappingHandlerMapping 继承图
RequestMappingHandlerMapping实现了 HandlerMapping 接口,同时还实现了 ApplicationContectAware 和 IntialingBean 接口。
ApplicationContextAware
这个接口只包含以下方法:
代码语言:javascript复制void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
如果一个类实现了 ApplicationContextAware 接口,Spring容器在初始化该类时候会自动回调该类的setApplicationContext()方法。这个接口主要用来让实现类得到Spring 容器上下文信息。
initializingBean 接口
这个接口包含下面方法:
代码语言:javascript复制void afterPropertiesSet() throws Exception;
如果一个bean实现了该接口,Spring 容器初始化bean时会回调afterPropertiesSet()方法。这个接口的主要作用是让bean在初始化时可以实现一些自定义的操作。
RequestMappingHandlerMapping 源码分析
RequestMappingHandlerMapping 实现了 ApplicationContextAware 接口 , 那么实例化后会执行 setApplicationContext 方法
代码语言:javascript复制 @Override
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
}
else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type [" requiredContextClass().getName() "]");
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
initApplicationContext(context);
}
else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is ["
this.applicationContext "], passed-in one is [" context "]");
}
}
}
这个方法把容器上下文赋值给 applicationContext 变量,赋值的就是 spring mvc 容器。
RequestMappingHandlerMapping 实现了 InitializingBean 接口。设置完属性后回调 afterpropertiesSet 方法.
代码语言:javascript复制 public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setTrailingSlashMatch(useTrailingSlashMatch());
this.config.setContentNegotiationManager(getContentNegotiationManager());
if (getPatternParser() != null) {
this.config.setPatternParser(getPatternParser());
Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch,
"Suffix pattern matching not supported with PathPatternParser.");
}
else {
this.config.setSuffixPatternMatch(useSuffixPatternMatch());
this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
this.config.setPathMatcher(getPathMatcher());
}
super.afterPropertiesSet();
}
同时还调用了父类的 afterPropertiesSet 方法
代码语言:javascript复制 public void afterPropertiesSet() {
//初始化handler函数
initHandlerMethods();
}
继续查看 RequestMappingHandlerMapping.initHandlerMethods 方法
代码语言:javascript复制protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " getApplicationContext());
}
//1.获取容器中所有bean 的name。
//根据detectHandlerMethodsInAncestorContexts bool变量的值判断是否获取父容器中的bean,默认为false。因此这里只获取Spring MVC容器中的bean,不去查找父容器
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
//循环遍历bean
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" beanName "'", ex);
}
}
//2.判断bean是否含有@Controller或者@RequestMappin注解
if (beanType != null && isHandler(beanType)) {
//3.对含有注解的bean进行处理,获取handler函数信息。
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
可以看出 RequestMappingHandlerMapping.initHandlerMethods 方法进行了如下操作:
- 获取Spring MVC 中的 bean
- 找出 含义 @Controller 和 @RequestMapping 的注解
- 对含义注解 bean 进行解析
查看 RequestMappingHandlerMapping.isHandle 处理逻辑
代码语言:javascript复制@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
看对含义 Controller 和 RequestMapping 的怎么处理
查看 RequestMappingHandlerMapping.detectHandlerMethods 方法
代码语言:javascript复制protected void detectHandlerMethods(final Object handler) {
//1.获取bean的类信息
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//2.遍历函数获取有@RequestMapping注解的函数信息
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
//如果有@RequestMapping注解,则获取函数映射信息
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class ["
userType.getName() "]: " method, ex);
}
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() " request handler methods found on " userType ": " methods);
}
//3.遍历映射函数列表,注册handler
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
//注册handler函数
registerHandlerMethod(handler, invocableMethod, mapping);
}
};
detectHandlerMethods 主要功能就是获取该bean和父接口中所有用@RequestMapping注解的函数信息,并把这些保存到methodMap变量中。
查看 RequestMappingHandlerMapping.selectMethods 方法实现逻辑
代码语言:javascript复制public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
final Map<Method, T> methodMap = new LinkedHashMap<Method, T>();
Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
Class<?> specificHandlerType = null;
//把自身类添加到handlerTypes中
if (!Proxy.isProxyClass(targetType)) {
handlerTypes.add(targetType);
specificHandlerType = targetType;
}
//获取该bean所有的接口,并添加到handlerTypes中
handlerTypes.addAll(Arrays.asList(targetType.getInterfaces()));
/对自己及所有实现接口类进行遍历
for (Class<?> currentHandlerType : handlerTypes) {
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
//获取函数映射信息
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
//循环获取类中的每个函数,通过回调处理
@Override
public void doWith(Method method) {
//对类中的每个函数进行处理
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
//回调inspect()方法给个函数生成RequestMappingInfo
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
//将生成的RequestMappingInfo保存到methodMap中
methodMap.put(specificMethod, result);
}
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
//返回保存函数映射信息后的methodMap
return methodMap;
}
上面逻辑中doWith()回调了inspect(),inspect()又回调了getMappingForMethod()方法。
我们看看getMappingForMethod()是如何生成函数信息的。
代码语言:javascript复制@Override
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);
}
}
return info;
}
查看RequestMappingHandlerMapping#createRequestMappingInfo()方法。
代码语言:javascript复制private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
//如果该函数含有@RequestMapping注解,则根据其注解信息生成RequestMapping实例,
//如果该函数没有@RequestMapping注解则返回空
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
//如果requestMapping不为空,则生成函数信息MAP后返回
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
看看RequestMappingHandlerMapping#createRequestMappingInfo是如何实现的。
代码语言:javascript复制protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, RequestCondition<?> customCondition) {
return RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name())
.customCondition(customCondition)
.options(this.config)
.build();
可以看到上面把RequestMapping注解中的信息都放到一个RequestMappingInfo实例中后返回。当生成含有@RequestMapping注解的函数映射信息后,最后一步是调用registerHandlerMethod 注册handler和处理函数映射关系。
代码语言:javascript复制protectedvoid registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
看到把所有的handler方法都注册到了mappingRegistry这个变量中。
到此就把RequestMappingHandlerMapping bean的实例化流程就分析完了。
Spring MVC容器初始化流程,查看在 FrameworkServlet#initWebApplicationContext 方法。
代码语言:javascript复制protected WebApplicationContext initWebApplicationContext() {
//1.获得rootWebApplicationContext
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
......
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
//2.创建 Spring 容器
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
//3.初始化容器
onRefresh(wac);
}
......
return wac;
}
查看 DispatchServlet#onRefresh 方法
代码语言:javascript复制 @Override
protected void onRefresh(ApplicationContext context) {
//执行初始化策略
initStrategies(context);
}
查看 initStrategies 方法
代码语言:javascript复制 protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
查看 initHandlerMappings 方法
代码语言:javascript复制private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
//容器中查找HandlerMapping的实例
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
//把找到的bean放到hanlderMappings中。
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");
}
}
}
最终是 实例化的 RequestMappingHandlerMapping 放到了一个 HandlerMapping 中。
服务请求是怎么处理的?
DispatchServlet 继承自Servlet,那所有的请求都会在service()方法中进行处理。
查看service()方法。
代码语言:javascript复制@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取请求方法
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
//若是patch请求执行此逻辑
if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
processRequest(request, response);
}
else {
//其它请求走此逻辑
super.service(request, response);
}
}
代码语言:javascript复制protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" getServletName() "'" resumed
" processing " request.getMethod() " request for [" getRequestUri(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<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 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());
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);
}
}
}
}
得到不管get、post最后都会执行到DispatcherServlet#doDispatch(request, response);
查看 doDispatch 方法
代码语言:javascript复制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.
mappedHandler = getHandler(processedRequest);
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;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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 = getHandler(processedRequest); 方法
代码语言:javascript复制protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//获取HandlerMapping实例
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" hm "] in DispatcherServlet with name '" getServletName() "'");
}
//得到处理请求的handler
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
上面遍历handlerMappings获得所有HandlerMapping实例,还记得handlerMappings变量吧,这就是前面initHandlerMappings()方法中设置进去的值,其实就是为了找到 RequestMappingHandlerMapping。
代码语言:javascript复制@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
......
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
......
return executionChain;
}
进入 AbstractHandlerMethodMapping#getHandlerInternal 方法
代码语言:javascript复制 @Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取函数url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
......
try {
//查找HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
......
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
进入 lookupHandlerMethod 方法
代码语言:javascript复制protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
......
}
最后从 mappingRegistry 找到对应的处理方法 这个 mappingRegistry 就是来自 实例化后的 RequestMappingHandlerMapping 。
总结
在初始化容器时,会 new 一个RequestMappingHandlerMapping,其父类是AbstractHandlerMethodMapping 。并把这个RequestMappingHandlerMapping 放到一个 HandlerMapping 中。
实例化后带有属性 mappingRegistry , mappingRegistry 的 value 指的是带有 requestMapping 注解的方法。
在服务请求时,遍历 HandlerMapping ,并根据请求信息,从RequestMappingHandlerMapping 中找到对应的处理方法handler
参考资料
- https://juejin.im/post/6844903829633253389
- https://www.cnblogs.com/grasp/p/11100124.html