分两个步骤解析springmvc
一,spring初始化
spring初始化的时候,把url和方法的映射,注册到urlLookup (LinkedMultiValueMap类型) 中
Web容器启动的时候,同时会启动Spring的IOC容器,RequestMappingHandlerMapping Bean也会随着IOC容器而实例化。RequestMappingHandlerMapping这个class覆盖了afterPropertiesSet方法。其超类AbstractHandlerMethodMapping的afterPropertiesSet方法代码如下:
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
再看initHandlerMethods方法:
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {// //获取IOC容器中所有Bean的名称(我们这里只讲用注解定义的bean)
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);//主要逻辑
}
}
handlerMethodsInitialized(getHandlerMethods());
}
再看processCandidateBean中代码实现:
protected void processCandidateBean(String beanName) {
。。。
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);//主要逻辑
}
}
detectHandlerMethods是核心方法。主要功能是组装bean,并注册到handlermethod集合中
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);//获取并组装meathod,例如get /activitiHistory/getInstancesByUserName
}
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);//注册到handlermethod集合中
});
}
}
再看registerHandlerMethod中代码实现:
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
调用注册方法,注册到一个LinkedMultiValueMap集合中,并设置成 类MappingRegistry的属性
public void register(T mapping, Object handler, Method method) {
。。。
for (String url : directUrls) {
this.urlLookup.add(url, mapping);//放入集合
}
。。。
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));//设置到MappingRegistry的属性中
}
二,用户请求调用
用户请求调用的时候,拿着url去urlLookup中获取要调用的方法实例
1,请求首先调用dispatcherservlet的doservice
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
。。。
try {
doDispatch(request, response);
}
。。。
}
下面是关键方法 doDispatch(request, response);
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
。。。
try {
。。。
mappedHandler = getHandler(processedRequest);//获取handler
。。。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
。。。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//执行handler
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
。。。。
}
}
首先 getHandler(processedRequest);是获取handler,进去看下
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);//这里
if (handler != null) {
return handler;
}
}
}
return null;
}
再看 mapping.getHandler(request);
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
。。。
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);//获取拦截器链
。。。
return executionChain;
}
再看Object handler = getHandlerInternal(request);
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);//这里
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
再跟进 lookupHandlerMethod(lookupPath, request);可以看到这里的mappingRegistry就是第一步初始化时候,带有urlLookup属性的类
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); //注意在这里的mappingRegistry
。。。
}
接下来就一目了然了
public List<T> getMappingsByUrl(String urlPath) {
return this.urlLookup.get(urlPath);
}
2,接下来就是执行handler和拦截器相关的代码
上面getHandler的方法中,获取handler同时获取了拦截器链
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
。。。
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);//获取拦截器链
。。。
return executionChain;
}
看getHandlerExecutionChain,该方法获取了自定义的HandlerInterceptor,添加到拦截器链中。(业务handler和自定义拦截器都在HandlerExecutionChain这个对象中)
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) { //this.adaptedInterceptors:自定义的HandlerInterceptor
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());//添加到拦截器链中
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
然后回到doDispatch方法中,下面对这个方法中的流程分析:
获取到HandlerExecutionChain类型对象mappedHandler 后,
先调用已注册HandlerInterceptor的preHandle()方法
再获取处理Handler的适配器
再真正执行handler(即Controller)对应的方法
后调用已注册HandlerInterceptor的postHandle()方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
。。。
try {
。。。
mappedHandler = getHandler(processedRequest);//获取handler
。。。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//获取适配器
。。。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
//调用已注册HandlerInterceptor的preHandle()方法
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//执行handler
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
//调用已注册HandlerInterceptor的postHandle()方法
}
。。。。
}
}
我们先看 getHandlerAdapter(mappedHandler.getHandler());选出该handler的处理适配器,
这里的 this.handlerAdapters是从DispatcherServlet.properties读出来的,主要有这几种
- AnnotationMethodHandlerAdapter主要是适配注解类处理器,注解类处理器就是我们经常使用的@Controller的这类处理器
2. HttpRequestHandlerAdapter主要是适配静态资源处理器,静态资源处理器就是实现了HttpRequestHandler接口的处理器,这类处理器的作用是处理通过SpringMVC来访问的静态资源的请求。
3.SimpleControllerHandlerAdapter是Controller处理适配器,适配实现了Controller接口或Controller接口子类的处理器,比如我们经常自己写的Controller来继承MultiActionController.
4.SimpleServletHandlerAdapter是Servlet处理适配器,适配实现了Servlet接口或Servlet的子类的处理器,我们不仅可以在web.xml里面配置Servlet,其实也可以用SpringMVC来配置Servlet,不过这个适配器很少用到,而且SpringMVC默认的适配器没有他,默认的是前面的三种。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
}
再看doDispatch 的 ha.handle(processedRequest, response, mappedHandler.getHandler());
真正执行业务
跟进去
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
跟((Controller) handler).handleRequest(request, response);
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
。 。。
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return handleRequestInternal(request, response);//执行
}
}
}
return handleRequestInternal(request, response);
}
跟handleRequestInternal(request, response);最后执行返回视图
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
。。。
ModelAndView modelAndView = new ModelAndView();
modelAndView.addAllObjects(RequestContextUtils.getInputFlashMap(request));//执行业务
if (viewName != null) {
modelAndView.setViewName(viewName);
}
else {
modelAndView.setView(getView());
}
return modelAndView;//返回视图
}