Commit 101c1853 by SunWei峰

给昨天补一个push,今天继续加油

parent ba2803d2
......@@ -71,20 +71,26 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 查找处理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
// 此处handler就是HandlerMethodReturnValueHandler的实现类
// HandlerMethodReturnValueHandler#handleReturnValue处理返回值
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
// returnValueHandlers就是HandlerMethodReturnValueHandler的实现类集合,默认有15个实现类
// 注意:returnValueHandlers是有顺序的
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
// 使用supportsReturnType方法判断该处理器是否支持解析当前返回值
if (handler.supportsReturnType(returnType)) {
return handler;
}
......
......@@ -1322,7 +1322,9 @@ public class DispatcherServlet extends FrameworkServlet {
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 这里的 HandlerMapping 如果没有特殊操作,则默认是从配置文件中读取并加载的 HandlerMapping
for (HandlerMapping mapping : this.handlerMappings) {
// 调用HandlerMapping 的getHandler 方法。
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
......
......@@ -75,9 +75,11 @@ public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHand
// Take any bean name that we can determine URLs for.
for (String beanName : beanNames) {
// 记录开头是 "/" 的 bean
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// URL paths found: Let's consider it a handler.
// 注册成handler
registerHandler(urls, beanName);
}
}
......
......@@ -495,7 +495,9 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 1. 调用 getHandlerInternal 获取 handler。该方法供子类实现。
Object handler = getHandlerInternal(request);
// 如果没有获取到 handler。则获取默认的handler
if (handler == null) {
handler = getDefaultHandler();
}
......@@ -503,6 +505,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
return null;
}
// Bean name or resolved handler?
// 如果 handler 是 String类型,则会认为是 beanName。从Spring容器中获取 bean实例
if (handler instanceof String handlerName) {
handler = obtainApplicationContext().getBean(handlerName);
}
......@@ -512,6 +515,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
initLookupPath(request);
}
// 2. 生成拦截器链路
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
......@@ -600,9 +604,11 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
* @see #getAdaptedInterceptors()
*/
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 构建一个执行链
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain handlerExecutionChain ?
handlerExecutionChain : new HandlerExecutionChain(handler));
// 遍历所有的拦截器,如果拦截器匹配符则加入到执行链中。adaptedInterceptors 是在 Mapping 初始化的时候加载的
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor mappedInterceptor) {
if (mappedInterceptor.matches(request)) {
......
......@@ -40,6 +40,7 @@ import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.MethodIntrospector;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
......@@ -220,11 +221,15 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
* @see #handlerMethodsInitialized
*/
protected void initHandlerMethods() {
// getCandidateBeanNames(): 从 Spring 容器中获取所有候选的beanName。
for (String beanName : getCandidateBeanNames()) {
// 如果beanName 不是以 SCOPED_TARGET_NAME_PREFIX 开头,则进行处理
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
// 1. 初始 候选的beanName
processCandidateBean(beanName);
}
}
// 这里就是打印了一下log日志
handlerMethodsInitialized(getHandlerMethods());
}
......@@ -262,7 +267,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
// 有 @controller 修饰或有 @RequestMapping修饰
if (beanType != null && isHandler(beanType)) {
// 筛选出合适的 HandlerMethod 注册
detectHandlerMethods(beanName);
}
}
......@@ -273,14 +280,19 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
* @see #getMappingForMethod
*/
protected void detectHandlerMethods(Object handler) {
// 获取 handlerType。这里传入的 handler如果是 String 就是 beanName,从上下文中获取type,否则就直接认为是 Handler
Class<?> handlerType = (handler instanceof String beanName ?
obtainApplicationContext().getType(beanName) : handler.getClass());
if (handlerType != null) {
// 返回给定类的用户定义类:通常只是给定的类,但对于CGLIB生成的子类,则返回原始类
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 遍历当前bean的所有方法,筛选出合适的 handler 方法 以及 注解信息
// 这里需要注意的是 MethodIntrospector.selectMethods 底层将 getMappingForMethod 返回为 null 的值给过滤掉了
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
// 供子类实现
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
......@@ -294,8 +306,11 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
else if (mappingsLogger.isDebugEnabled()) {
mappingsLogger.debug(formatMappings(userType, methods));
}
// 遍历所有的 methods(这里的 methods 经过上面的筛选后,都是被 @RequestMapping 注解修饰的方法)
methods.forEach((method, mapping) -> {
// 这里是针对 cglib 代理特殊处理
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
//注册 HandlerMethod
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
......@@ -377,9 +392,11 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
@Override
@Nullable
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 从 request 中解析出 请求路径
String lookupPath = initLookupPath(request);
this.mappingRegistry.acquireReadLock();
try {
// 查找 HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
......@@ -399,16 +416,25 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
*/
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
// 通过 url 获取匹配路径
// springMVC 会在初始化的时候建立 URL 和相应 RequestMappingInfo 的映射,这点在上面的解析中我们可以知道。
// 如果不是restful接口,这里就可以直接获取到。
// 这里是通过 urlLookup 获取的 RequestMappingInfo
List<Match> matches = new ArrayList<>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
// 将匹配的 Mapping 保存到 matches 中。
addMatchingMappings(directPathMatches, matches, request);
}
// 如果上面没有获取到匹配的路径,则只能遍历所有的 mapping。
// 由于会遍历所有的 RequestMapping。所以性能会随着 RequestMapping 数量的增加降低
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
// 如果 matches 不为空,则说明有匹配的 Mapping
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
// 如果合适的 Mapping 不止一个,则筛选出最合适的
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
......@@ -628,28 +654,40 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
}
public void register(T mapping, Object handler, Method method) {
// 加写锁
this.readWriteLock.writeLock().lock();
try {
// 将 handler 和 method 封装成一个 HandlerMethod 实例
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
// 校验实例的合法性。即唯一性
validateMethodMapping(handlerMethod, mapping);
// 获取url映射,如果是 restful 请求则获取不到。建立 url 和Mapping 的映射。
// 一个mapping 可以对应多个url
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
// 这里将url 和 mapping映射起来
// 在进行匹配的时候,就是先根据url找到合适的mapping,然后根据找到的mapping再去找到HandlerMethod
for (String path : directPaths) {
this.pathLookup.add(path, mapping);
}
// 保存 类名#方法名 : HandlerMethod 的映射关系
String name = null;
if (getNamingStrategy() != null) {
// 这里解析出来的 name 并不是完整的类名,而是类名的首字母组合。比如方法名是 DemoController.say(),
// 解析出来的name即为 DC#say。如果是 SayController.say()。解析出来则为 name = SC#say
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
// @CrossOrigin 跨域注解请求的初始化配置
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
corsConfig.validateAllowCredentials();
this.corsLookup.put(handlerMethod, corsConfig);
}
// 保存到 registry 中
this.registry.put(mapping,
new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
}
......
......@@ -409,6 +409,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
Object resolvedHandler = handler;
// Eagerly resolve handler if referencing singleton via name.
// 如果不是懒加载 && handler 是 String 类型。
if (!this.lazyInitHandlers && handler instanceof String handlerName) {
ApplicationContext applicationContext = obtainApplicationContext();
if (applicationContext.isSingleton(handlerName)) {
......@@ -416,6 +417,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
}
}
// 判断 handlerMap 中已经保存了该 url
Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
......@@ -425,12 +427,14 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
}
}
else {
// 如果是 urlPath 是 "/" 开头。则设置为根处理器
if (urlPath.equals("/")) {
if (logger.isTraceEnabled()) {
logger.trace("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
// 如果是 urlPath 是 "/*" 开头。则设置为 默认处理器
else if (urlPath.equals("/*")) {
if (logger.isTraceEnabled()) {
logger.trace("Default mapping to " + getHandlerDescription(handler));
......@@ -438,6 +442,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
setDefaultHandler(resolvedHandler);
}
else {
// 否则的话,保存到 handlerMap 中
this.handlerMap.put(urlPath, resolvedHandler);
if (getPatternParser() != null) {
this.pathPatternHandlerMap.put(getPatternParser().parse(urlPath), resolvedHandler);
......
......@@ -187,6 +187,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
@Override
@SuppressWarnings("deprecation")
public void afterPropertiesSet() {
// 进行 RequestMapping 的配置
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setTrailingSlashMatch(useTrailingSlashMatch());
this.config.setContentNegotiationManager(getContentNegotiationManager());
......@@ -202,6 +203,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
this.config.setPathMatcher(getPathMatcher());
}
// 调用父类的 afterPropertiesSet 方法。
super.afterPropertiesSet();
}
......@@ -279,12 +281,17 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 转换成 RequestMappingInfo,如果方法没有被 @RequestMapping 注解修饰,则会返回null
// 解析出来 方法 上 @RequestMapping 注解的各种信息
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 解析出来 bean 上 @RequestMapping 注解的各种信息
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 合并类和方法的 @RequestMapping 注解信息
info = typeInfo.combine(info);
}
// 获取前缀,拼接前缀
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
......@@ -316,9 +323,12 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
*/
@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
// 获取当前方法上的 @RequestMapping 注解
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
// 获取自定义的方法条件
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
// 这里可以看到: 如果 requestMapping = null,则会直接返回 null,否则会封装成一个 RequestMappingInfo (包含 @RequestMapping 注解的各种参数) 返回。
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
......@@ -420,6 +430,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
}
private void updateConsumesCondition(RequestMappingInfo info, Method method) {
// 对 @RequestBody 注解进行了进一步解析
ConsumesRequestCondition condition = info.getConsumesCondition();
if (!condition.isEmpty()) {
for (Parameter parameter : method.getParameters()) {
......
......@@ -114,6 +114,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 调用handler(controller+method),得到返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
......@@ -132,6 +133,8 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 处理返回值方法
// returnValueHandlers是HandlerMethodReturnValueHandlerComposite类
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
......
......@@ -18,12 +18,7 @@ package org.springframework.web.servlet.view;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.*;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment