HandlerMethod类 |注册Handler
InvocableHandlerMethod
对请求进行处理
- WebDataBinderFactory
- HandlerMethodArgumentResolverComposite
ServletInvocableHandlerMethod
处理返回值
- HandlerMethodReturnValueHandlerComposite
MethodParameter[] parameters
封装了参数信息:参数的的索引位置,类型,注解,参数名等信息
RequestCondition
各种condition,其中RequestMappingInfo类似代理类,类似condition集合。
AbStractHandlerMethodMapping
AbstractHandlerMethodMapping implements InitializingBean
初始化阶段会执行afterPropertiesSet() 方法。
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
initHandlerMethods()
从ApplicationContext中检测,注册HandlerMethods
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #isHandler(Class)
* @see #getMappingForMethod(Method, Class)
* @see #handlerMethodsInitialized(Map)
*/
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//找出容器中的所有类。
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
//排除scopedTarget.开头的bean
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);
}
}
//isHandler()检测是否是handler,模版方法
//RequestMappingHandlerMapping.isHandler() 判断是否是@controller 或者 @RequestMapping
if (beanType != null && isHandler(beanType)) {
//查找HandlerMethods
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
detectHandlerMethods()
/**
* Look for handler methods in a handler.
* @param handler the bean name of a handler or a handler instance
*/
//传进来的是beanName
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
//针对CGLIB生成的子类,找到真正用户定义的类型userType
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//从Class中获取<Method,RequestMappingInfo>
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
//RequestMappingHandlerMapping.getMappingForMethod(),构造getMappingForMethod
//
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);
}
for (Map.Entry<Method, T> entry : methods.entrySet()) {
//判断Method是否可调用(不是private方法)
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
//RequestMappingInfo(方法上的信息)
T mapping = entry.getValue();
//注册到AbstractHandlerMethodMapping.MappingRegistry属性中。
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
RequestMappingHandlerMapping.getMappingForMethod()
用来创造RequestMappingInfo的
/**
* Uses method and type-level @{@link RequestMapping} annotations to create
* the RequestMappingInfo.
* @return the created RequestMappingInfo, or {@code null} if the method
* does not have a {@code @RequestMapping} annotation.
* @see #getCustomMethodCondition(Method)
* @see #getCustomTypeCondition(Class)
*/
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
//先从method中获取info
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
//不为空,再从Class中获取Info
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
//最后combine
info = typeInfo.combine(info);
}
}
return info;
}
RequestMappingHandlerMapping.createRequestMappingInfo
/**
* Delegates to {@link #createRequestMappingInfo(RequestMapping, RequestCondition)},
* supplying the appropriate custom {@link RequestCondition} depending on whether
* the supplied {@code annotatedElement} is a class or method.
* @see #getCustomTypeCondition(Class)
* @see #getCustomMethodCondition(Method)
*/
//获取RequestMappingInfo
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
//获取自定义Condition,可以自定义,参见https://app.yinxiang.com/shard/s47/nl/20202808/83224da8-631d-4d1a-a586-9ac56564d74b
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
//主要就是将@RequestMapping中大部分信息设置到RequestMappingInfo中
//并且构造各种condition,
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
AbstractHandlerMethodMapping.register
设计到的MappingRegistry中的Map
//<RequestMappingInfo,MappingRegistration>
private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();
//<RequestMappingInfo,HandlerMethod>
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();
//<url,RequestMappingInfo>
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();
//RequestMappingInfo.Name或HandlerMethod的name, List<HandlerMethod>
private final Map<String, List<HandlerMethod>> nameLookup =
new ConcurrentHashMap<String, List<HandlerMethod>>();
private final Map<HandlerMethod, CorsConfiguration> corsLookup =
new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();
//注册mapping是RequestMappingInfo
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
//构造HandlerMethod
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
//确认唯一的mapping
assertUniqueMethodMapping(handlerMethod, mapping);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
//放入mappingLookup中,<RequestMappingInfo,HandlerMethod>
this.mappingLookup.put(mapping, handlerMethod);
//获取url,从RequestMappingInfo的PatternsCondition中获取。
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
//<url,RequestMappingInfo>
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
//命名策略
// For example "TC#getFoo" * for a class named TestController with method getFoo.
//RequestMappingInfo的name不为空则返回其name,如果为空,按照命名策略定义一个名字,例如“TC#foo”
name = getNamingStrategy().getName(handlerMethod, mapping);
//this.nameLookup.put(name, List<HandlerMethod>);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
//<RequestMappingInfo,MappingRegistration>
this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
RequestMappingHandlerMapping
/**
* Creates {@link RequestMappingInfo} instances from type and method-level
* {@link RequestMapping @RequestMapping} annotations in
* {@link Controller @Controller} classes.
*/
DispatcherServlet() | 获取Handler
protected void doDispatch(HttpServletRequest request, HttpServletResponse response){
...
mappedHandler = getHandler(processedRequest);
...
}
getHandler中使用DispatcherServlet 中配置的 List<HandlerMapping> handlerMappings;
来获取handler
//org.springframework.web.servlet.DispatcherServlet#getHandler
HandlerExecutionChain handler = hm.getHandler(request);
AbstractHandlerMapping#getHandler()
HandlerMapping的getHandler()方法由抽象类AbstractHandlerMapping实现
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//根据request获取handler,此处handler是handlerMethod
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;
}
getHandlerInternal(request);为AbstractHandlerMapping的抽象方法
AbstractHandlerMapping类继承关系
AbstractHandlerMethodMapping 和 AbstractUrlHandlerMapping
AbstractHandlerMethodMapping#getHandlerInternal()
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取path,从request获取contextPath + RequestUri + RemainingPath
/**
* Return the path within the servlet mapping for the given request,
* i.e. the part of the request's URL beyond the part that called the servlet,
* or "" if the whole URL has been used to identify the servlet.
* <p>Detects include request URL if called within a RequestDispatcher include.
* <p>E.g.: servlet mapping = "/*"; request URI = "/test/a" -> "/test/a".
* <p>E.g.: servlet mapping = "/"; request URI = "/test/a" -> "/test/a".
* <p>E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a".
* <p>E.g.: servlet mapping = "/test"; request URI = "/test" -> "".
* <p>E.g.: servlet mapping = "/*.test"; request URI = "/a.test" -> "".
* @param request current HTTP request
* @return the path within the servlet mapping, or ""
*/
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
//加读锁
this.mappingRegistry.acquireReadLock();
try {
//根据path找HandlerMethod
// 从mappingRegistry.urlLookup()中根据url找到对应的List<RequestMappingInfo>
//遍历 RequestMappingInfo,RequestMappingInfo中有各种condition,根据requst看各个RequestMappingInfo与requst是否匹配,匹配的话构造一个新的RequestMappingInfo返回。
//根据新构造的RequestMappingInfo和从mappingRegistry.getMappings中根据request获取的HandleMehtod,构造Match对象,并加入到List<Match>中。
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);//↓
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
//释放锁
this.mappingRegistry.releaseReadLock();
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
//url -> RequestMappingInfo (从urlLookup中),多值map
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//directPathMatche就是RequestMappingInfo
//(directPathMatche,request) -> new RequestMappingInfo() //检测是否所有的condition 与提供的request匹配。
//mappingRegistry.mappingLookup().get(directPathMatche) -> HandleMethod (this.mappingLookup)
//(new RequestMappingInfo(),HandleMethod) -> Match -> List<Match>
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()) {
//构造比较器,比较方法最终调用各个condition的compare方法
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
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();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
//将匹配的LookupPath放入request中?有啥用?
handleMatch(bestMatch.mapping, lookupPath, request);
//Match中有HandlerMethod,返回对应的HandlerMethod
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
AbstractHandlerMapping#getHandlerExecutionChain
/**
* Build a {@link HandlerExecutionChain} for the given handler, including
* applicable interceptors.
* <p>The default implementation builds a standard {@link HandlerExecutionChain}
* with the given handler, the handler mapping's common interceptors, and any
* {@link MappedInterceptor}s matching to the current request URL. Interceptors
* are added in the order they were registered. Subclasses may override this
* in order to extend/rearrange the list of interceptors.
* <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
* pre-built {@link HandlerExecutionChain}. This method should handle those
* two cases explicitly, either building a new {@link HandlerExecutionChain}
* or extending the existing chain.
* <p>For simply adding an interceptor in a custom subclass, consider calling
* {@code super.getHandlerExecutionChain(handler, request)} and invoking
* {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
* @param handler the resolved handler instance (never {@code null})
* @param request current HTTP request
* @return the HandlerExecutionChain (never {@code null})
* @see #getAdaptedInterceptors()
*/
//主要就是给handler设置interceptor
//传入的handler可能是handler(HandlerMethod)或者HandlerExecutionChain
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;
}
资源文件映射
<mvc:resources location="/static/" mapping="/static/**"/>
Spring 使用 ResourcesBeanDefinitionParser 解析 xml 实例化SimpleUrlHandlerMapping,注册handlerMethod为ResourceHttpRequestHandler。
ResourceHttpRequestHandler进行handleRequest的时候,直接输出资源文件的文本内容。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。