Spring MVC学习笔记二
Spring MVC学习笔记二
上次我们说到了RequestMappingHandlerMapping继承自AbstractHandlerMethodMapping的方法来完成找到被@RequestMapping注解标注的类和其中的方法,并且将注解里面配置的url和方法一一对应起来,但是我们还没讲到拿到这个映射关系后Spring是怎么存储这个映射关系的。上次我们没有把寻找方法和url映射的方法给拿出来,这里也贴出来。
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 这里用lambda表达式来遍历userType对象里面所有的方法
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));
}
else if (mappingsLogger.isDebugEnabled()) {
mappingsLogger.debug(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 这里就是用一个成员变量存储这个映射关系
// private final MappingRegistry mappingRegistry = new MappingRegistry();
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
// 这个方法是让RequestMappingHandlerMapping来实现的
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 这里是取方法上的@RequestMapping注解的信息
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 这里是取类上面的注解信息
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 拼接成完整的url
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
为了忘记RequestMappingHandlerMapping的继承结构,又把图放在这里
可以看到这些类继承了ApplicationContextAware接口,当Spring启动过程中会去扫描那些继承了Aware接口的实现,然后执行这些实现类的某些初始化方法,比如ApplicatrionContextAware的子实现就会执行setApplicationContext()方法,这里可以看一下ApplicationContextAware接口
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
而和SpringMVC有关的拦截器初始化就在上面继承图里面ApplicationObjectSupport类的setApplicationContext方法里面,然后这个方法里面会调用一个叫initApplication方法,这个方法的实现在AbstractHandlerMapping类里面
@Override
protected void initApplicationContext() throws BeansException {
// 空实现
extendInterceptors(this.interceptors);
// 解析容器中的MappedInterceptor对象
detectMappedInterceptors(this.adaptedInterceptors);
// 处理如果有WebRequestInterceptor的情况
initInterceptors();
}
// 这个方法就是将这些能扫描到的拦截类放到一个成员变量中
// private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();
这里我们就得到了配置的拦截器,然后后面就是怎么拿到这些拦截器构成一个拦截器链路在请求的时候执行拦截逻辑了,这个很像Servlet里面的Fiiter,后面我们可以一起看一下这两者有啥不同,不过今晚就先这样咯,后面我们介绍拦截器起作用的代码。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本