一次请求的源码分析过程
<!-- **********************下次处理:为什么我们请求后,解析处理返回ModelAndView,那为什么我们有时候在请求controller后返回一个json数据,有的是一个页面,
这块springmvc是怎么处理的,是否支持一些别的扩展,
-->
<!--
最后 ****
拿到中置拦截器处理得到的ModelAndView 处理程序选择和处理程序调用的结果 模型和视图,或者是一个可以解析为模型和视图的异常。
DispatcherServlet.processDispatchResult();
//处理数据请求响应处理结束,http连接断开,释放资源
-->
<!--
过后就是中置拦截器
interceptor.postHandle
视图解析器,从ModelAndView中解析
ViewResolve
后置拦截器(关闭连接,释放资源)
interceptor.afterCompleton
-->
<!--
HandlerAdapter.handle()
适配器去调用具体的controller处理器
// 实际调用处理程序。
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
RequestMappingHandlerAdapter.invokeHandleMethod() //去调用这个实际的HandleMethod,就是方法调用
//注定参数解析多种多样
InvocableHandlerMethod.getMethodArgumentValues() //获取这些method方法参数的值,并解析处理
//拿到所有参数
MethodParameter[] parameters = getMethodParameters();
//请求通过requst对象中传入入参值,封装成数组,拿到之前的method对象,通过method.invoke(bean, args); //arg数组来调用具体的方法
//可以扩展,不同的参数类型对应不同的处理类*** 重要
// 参数解析处理逻辑
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
}
throw ex;
}
}
HandlerMethodArgumentResolver //扩展解析参数处理类的最顶层接口
//argumentResolvers 这个是什么时候初始化的,是在启动的时候初始化的,也是通过initBean来加载初始化注册的
//解答:在这个类中通过InitializingBean来初始化的
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
getDefaultArgumentResolvers //这个方法完成初始化
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
parameter.getGenericParameterType() + "]");
}
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
//通过这个methodArgumentResolver.supportsParameter(parameter) 可以查看到默认支持的参数解析有哪些
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
//获取request中的参数,并解析处理参数,处理完返回请求参数去调用具体的method方法,通过invoke
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
Object returnValue = invoke(args);
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel(); //ModelAndViewContainer的封装
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav; //返回结果集和页面
}
ModelAndView //再给后置拦截器去显示解析返回给浏览器
-->
<!--
前置拦截器,拦截请求,true或false
当mappedHandler.applyPreHandle(processedRequest, response)返回false,就不往下执行了
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
-->
<!--
handlerAdapter - 负责去调用具体的controller里面的方法的,contrller中有多个方法,handlerAdapter去决定调用哪个方法
适配参数,如何二个参数的方法,三个参数的方法,参数的格式和类型肯定不一样,所有handlerAdapter可以解析我们的处理器
方法的参数,这里使用的是一个策略模式
和返回去参数的解析,返回参数的解析也是通过策略模式去解析返回参数,比如controller
中不同方法的返回参数类型,如string void map 等
//为当前请求确定处理程序适配器。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//这里会根据具体的HandlerMethod去找到一个具体的HandlerAdapter适配器,spring在启动的时候就会默认注册4个HandlerAdapter
if (ha.supports(handler)) { //策略模式的使用,方便扩展,使用不同的handler可以循环去找到对应的HandlerAdapter
return ha;
}
interceptorIndex //由于拦截器是一个链式结构
//TODO 扩展拦截器的认识
//调用每个拦截器的前置拦截器
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
if (!interceptor.preHandle(request, response, this.handler)) {
//1.首先先去调用这个拦截器的preHandle()方法
//当这个拦截器是怎么时候注册进来的,自定义要如何写???
}
this.interceptorIndex = i; //给所有的拦截器编号 0, 1 , 2
}
}
//调用每个拦截器的中置拦截器
for (int i = getInterceptors().length - 1; i >= 0; i ————) {
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.postHandle(request, response, this.handler, mv);
// 2.调用中置拦截器
// 调用顺序 3, 2, 1
//调用后置拦截器
for (int i = this.interceptorIndex; i >= 0; i————) {
HandlerInterceptor interceptor = getInterceptors()[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
//3. 调用后置拦截器
//调用顺序 3,2, 1
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
-->
<!-- 如: /session/login 请求路径
/session 能确定一个controller
/login 能确定一个method
DispatcherServlet 本身就是一个servlet,所以请求过来首先会访问它父类FrameworkServlet.service()方法 > DispatcherServlet.doDispatch()
mappedHandler = getHandler(processedRequest); //获取当前请求的处理器,并包装成HandlerExecutionChain
//遍历启动时注册的handlerMappings 并为每一个handlerMappings包装成一个处理类
for (HandlerMapping hm : this.handlerMappings) { handlerExecutionChain handler = hm.getHandler(request);}
//查找给定请求的处理程序方法。
AbstractHandlerMethodMapping.getHandlerInternal()
//拿到请求url /session/login
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
//根据url来拿到HandlerMethod对象
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
//urlMap 是一个url和控制器中的方法 url:控制器方法类解析数值 map 就是url和HandlerMethod的映射,那是什么时候加上的注册,那肯定是在启动的时候就注册到map中的
List<T> directPathMatches = this.urlMap.get(lookupPath);
//handlerMethod中建立一个url和controller中login()方法定映射,那映射是什么时候建立的了,还是在容器初始化是就建立了
Map<T, HandlerMethod> handlerMehod = this.handlerMethods();
//this.handlerMethods() 是这个类中的一个map,这个抽象类继承了InitializingBean,重点落在这个类中了
//所以会在实例化该类调用afterPropertiesSet().initHandlerMethods();这个方法来完成handlerMehod的初始化
AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean
//循环遍历在初始化时注册到容器的beans数据集合并遍历去判断存在@Controller和@RequestMapping的bean
String[] beanNames
//先通过beanName来获取容器中的Class<?>反射对象,并用Class对象来匹配是否存在如下二个注解的类
@Override
protected boolean isHandler(Class<?> beanType) {
return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
(AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
}
//判断过后,detectHandlerMethods(beanName);这个方法只会走带有注解的类
//相当于过滤,因为只有控制器才有url和方法的映射
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) &&
isHandler(getApplicationContext().getType(beanName))){
detectHandlerMethods(beanName);
}
}
final Map<Method, T> mappings = new IdentityHashMap<Method, T>();
Method:CommitteeActivityController.AddInfo(param)
T:
{
[/committee/activity//activity],
methods=[GET],
params=[],
headers=[],
consumes=[],
produces=[],
custom=[]
}
//先拿到对应类的Class对象,并获取该类下的所有方法
//new MethodFilter() 采用匿名类的方式来过滤method
Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
@Override
public boolean matches(Method method) {
T mapping = getMappingForMethod(method, userType);
if (mapping != null) {
mappings.put(method, mapping);
return true;
}
else {
return false;
}
}
});
//并注册到this.handlerMethods.put(mapping, newHandlerMethod); map中
for (Method method : methods) {
registerHandlerMethod(handler, method, mappings.get(method));
}
//将HandlerMethod封装到handlerExecutionChain中
return getHandlerExecutionChain(handler, request);
//TODO 10.10 propress doWith() 54:13
//迭代继续寻找父类中的方法
ReflectionUtils.doWithMethods()
if (clazz.getSuperclass() != null) {
doWithMethods(clazz.getSuperclass(), mc, mf);
}
//迭代继续寻找接口的方法
else if (clazz.isInterface()) {
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
//拿到带有@RequestMapping的方法,获取注解上的属性
AbstractHandlerMethodMapping.getMappingForMethod()
RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
//拿到注解上的属性
String[] params() default {};
//包装method的参数信息
RequestMappingInfo info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
//封装成实体
return new RequestMappingInfo(
new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
new RequestMethodsRequestCondition(annotation.method()),
new ParamsRequestCondition(annotation.params()),
new HeadersRequestCondition(annotation.headers()),
new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
new ProducesRequestCondition(annotation.produces(), annotation.headers(), this.contentNegotiationManager),
customCondition);
//先循环每一个bean,扫描到有@Controller和@RequestMapping注解的类,并扫描对应类中的所有方法(包括父类和接口的)
//注册Map<Method, T>的对应关系,然后遍历这些newHandlerMethod把它和mapping T 建立map关系于handlerMethods中
this.handlerMethods.put(mapping, newHandlerMethod);
//请求过来就直接去注册的map中去找对应的url就能匹配到对应的类和类的信息
//回归正常的请求流程(如上是启动的自动initBean接口时自动注册到map的初始化流程)4
//根据请求的url去handlerMethods去获取对应的HandlerMethod对象
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
//将获取到的HandlerMethod又封装到Match对象中
Object handler = getHandlerInternal(request); //拿到对应请求url的HandlerMethod对象
//又将HandlerMethod 封装到HandlerExecutionChain
return getHandlerExecutionChain(handler, request);
//将所有的拦截器都添加到Handler处理器中
chain.addInterceptors(getAdaptedInterceptors());
HandlerInterceptor//类中存在前,中,后置拦截器
// HandlerExecutionChain中有如下二个属性
private final Object handler; //HandlerMethod
private HandlerInterceptor[] interceptors; //拦截器
-->
<!-- 定义HandlerMapping(请求的url:handlerMethod【controller中的方法】)的对应关系
这个关系都是第一次都是第一次请求过来以后就建立映射关系,并放到内存map中去,方便下次直接查找使用,
1.先判断是否支持HandlerMapping
2.从自定义实现HandlerMapping中去找子类
3.从注册的bean中找id等于handlerMapping的HandlerMapping
4.用默认的HandlerMapping来,是 spring自己配置,有二个默认配置
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean> -->