不要问我阅读spring源码有什么用,问就是没有用,只是让我自己使用spring的过程中自信点!
相关文章
相关链接
- spring-mvc-handlerMapping 是怎么存放我们的请求路径的-源码
- springmvc-执行流程
- spring-mvc 时如何选择 messageConverter
- springMVC-Interceptor-源码分析
映射关系是在哪里拿到的
首先有几个类
- HandlerExecutionChain , 这个是执行链
- HandlerMethod 这个就是我们常用的请求的封装(也是本文的目标)
- HandlerAdapter 适配器(处理请求的就是从它开始)
- HandlerExecutionChain.handler 属性 就是 HandlerMethod
- HandlerAdapter 中最后执行的也是 ServletInvocableHandlerMethod 也是从 HandlerMethod 封装的
说明: 本文只对 HandlerMethod 的获取进行分析,不对mvc的执行流程分析,所有的一起源码都是针对常见的请求(@Controller 和 @RequestMapping)
HandlerMethod的获取
上面已经知道了最后执行的是HandlerExecutionChain.handler,那就看看这个属性是如何被赋值的
方法入口为DispatcherServlet.doDispatch.getHandler()
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.
//就是在这个地方获取的 handlerExecutionChain,也是在这里获取的 handlerMethod
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());
.....................................
}
上述代码 删除无关代码,继续往下:
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
//文章开头说了 handlerMethod 是在 handlerExceutionChain 中,所以在这个代码里
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//就是在这里获取的 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 = obtainApplicationContext().getBean(handlerName);
}
//获取 执行链 把 handlerMethod 放入 HandlerExecutionChain
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;
}
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//根据request 获取 请求路径 里面东西还挺多,不多也就是获取路径的
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
//获取 handlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
//这里根据请求路径获取requsetMappingInfo 格式为 [{GET /xml, produces [application/xml]}]
//请求方式,请求路径,响应类型 注意 现在这个类 是requestMappingHandlerMapping 的一个父类
// 说明 这也信息有可能是在 requestMappingHandlerMapping 初始化的时候放进去的.
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//获取 Match 的方法 Match 中包含 HandlerMethod
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);
// 发现返回的 handlerMethod 是 Match 属性 所以我们关注 matches 就行了
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
//这里又去获取了一次 requestMappingInfo 我以为不知道为啥又去获取了一次
T match = getMatchingMapping(mapping, request);
if (match != null) {
//这里创建了Match 点进去发现传了两个参数 一个是requestMapping 一个是 HandlerMethod
//现在主要看下 this.mappingRegistry.getMappings().get(mapping))
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
public Map<T, HandlerMethod> getMappings() {
return this.mappingLookup;
}
//到这里可以看到了 HandlerMethod 是从mappingLookup获取的
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
下面就要mappingLookup是什么时候被赋值的
mappingLookup 是 MappingRegistry 的属性 MappingRegistry 是 AbstractHandlerMethodMapping的内部类
映射关系是在哪里被加载进去的
思路: 在MappingRegistry.put() 的地方debug,观察执行栈
重要执行节点:requestMappingHandlerMapping初始化-> afterPropertiesSet()
- requestMappingHandlerMapping初始化就不看了,是spring-ioc 的东西,以后会讲
- requestMappingHandlerMapping的父类AbstractHandlerMethodMapping实现了InitializingBean接口
- spring bean 初始化之后 会执行 @PostConstruct 注解的 方法 实现了InitializingBean接口 的afterPropertiesSet()方法,我们这里用到的是InitializingBean
贴代码如下:
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);
}
}
}
@Override
public void afterPropertiesSet() {
//这堆配置 具体是啥我也不知道
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
//看这里,调用了父类的 afterPropertiesSet();
super.afterPropertiesSet();();
}
@Override
public void afterPropertiesSet() {
//这里
initHandlerMethods();
}
//这里
protected void initHandlerMethods() {
//getCandidateBeanNames() 应该是获取了所有的beanName
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
//就是这里
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
//根绝beanName处理的
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
//获取当前bean的class 类型
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);
}
}
//这里 重点 isHandler() 判断是否需要处理
if (beanType != null && isHandler(beanType)) {
//假如是的话,继续 (重点)
detectHandlerMethods(beanName);
}
}
// 看到了,条件就是 当前类是否存在 @Controller @RequestMapping 注解
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
下面的代码就是最后了,注意看! 下面的代码比较绕,用的是java8的Lambda 表达式,假如对java8比较熟,看这段代码是无压力的 先把这几个方法的代码都贴出来,如下:
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
//获取当前contorller 类型
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 第一步 就是这里 执行selectMethods 这个方法 传递了一个行为(lambda表达式)
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);
});
}
}
public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
final Map<Method, T> methodMap = new LinkedHashMap<>();
Set<Class<?>> handlerTypes = new LinkedHashSet<>();
Class<?> specificHandlerType = null;
//判断是否存在代理
if (!Proxy.isProxyClass(targetType)) {
specificHandlerType = ClassUtils.getUserClass(targetType);
handlerTypes.add(specificHandlerType);
}
handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
//循环 第二步 目标 controller 正常情况就一个元素
for (Class<?> currentHandlerType : handlerTypes) {
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
// 调用 doWithMethods 第三步
ReflectionUtils.doWithMethods(currentHandlerType, method -> {
//第五步 获取到了 method
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
methodMap.put(specificMethod, result);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
return methodMap;
}
public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
// Keep backing up the inheritance hierarchy.
//获取所有的方法
Method[] methods = getDeclaredMethods(clazz);
for (Method method : methods) {
if (mf != null && !mf.matches(method)) {
continue;
}
try {
//执行 selectMethods 方法中的 MethodFilter mf 第四步
mc.doWith(method);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
}
}
if (clazz.getSuperclass() != null) {
doWithMethods(clazz.getSuperclass(), mc, mf);
}
else if (clazz.isInterface()) {
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
}
//保存对应关系入口
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
//结束了
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
//保存到 mappingLookup
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
//保存路径到urlLookup
this.urlLookup.add(url, mapping);
}
//
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
总结:
- spring-ioc 初始化 requestMappingHandlerMapping 的时候 把对应关系 存放在mappingLookup
- 执行的时候 根绝请求路径 查找urlLookup,再根据 urlLookup 的val 当做key 去 mappingLookup 中查找