springmvc 如何做URL映射关系
1.SpringIOC容器加载时开始遍历所有的bean对象 判断 bean对象 类上是否有加上
@Controller注解,如果类上有加该注解的话 则该类就是为我们控制类;
2.在容器初始化时会建立所有url和controller的对应关系,利用java反射机制,查找该控制类中所有方法,判断方法上是否有加上@RequestMapping注解,如果有加上该注解的话 保存到Map<url,controller>中(key=/mayiktDemo01,MayiktController#mayiktDemo01())
3.定义DispatcherServlet 接受客户端所有请求 从该map集合中查找到具体的控制类 方法 调用(java反射机制调用)
springmvc 请求映射原理
SpringMVC 前端控制器 DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;// Handler 责任链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);//根据请求路径 获取对应的Handler责任链(处理器)mappedHandler = getHandler(processedRequest);、// 如果没有查找到的情况下 则返回404if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}//根据对应的Handler 获取对应的适配器HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//根据适配器执行请求方法//mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
责任链设计模式 具体流程
springmvc 拦截器
拦截器A
拦截器B
拦截器C
public String demo01() {
}
1、用户向服务器发送请求,请求会先达到 SpringMVC 前端控制器 DispatcherServlet ;
2、DispatcherServlet 根据该 URI,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以 HandlerExecutionChain 执行链对象的形式返回
3、DispatcherServlet 根据获得的 Handler,获取对应的 HandlerAdapter;
5、获取到 HandlerAdapter,将开始执行拦截器的 preHandler(…)方法;
6、提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller)方法,处理请求,在填充 Handler 的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:
HttpMessageConveter:将请求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的类型信息
数据转换:对请求消息进行数据转换。如 String 转换成 Integer、Double 等
数据格式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等
数据验证:验证数据的有效性(长度、格式等),验证结果存储到 BindingResult 或 Error 中
7、Handler 方法执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象。
8、开始执行拦截器的 postHandle(…)方
9、根据返回的 ModelAndView(此时会判断是否存在异常:如果存在异常,则执行 HandlerExceptionResolver 进行异常处理)选择一个适合的 ViewResolver 进行视图解析,根据 Model 和 View,来渲染视图
10、渲染视图完毕执行拦截器的 afterCompletion(…)方法
11、将渲染结果返回给客户端
HandlerMappings
1.实现Controller方式所使用的适配器
2.实现HTTP请求处理器的适配器:HttpRequestHandlerAdapter
3.注解方式(@Controller)的处理器适配器:
4.实现servlet方式的适配器:
HandlerMapping 负责解析请求URL
HandlerMapping的分类
SpingMVC中的HandlerMapping负责解析请求URL,对应到Handler进行处理(这里的Handler一般为Controller里的一个方法method,也可以为servlet或者Controller等)
1.RequestMappingHandlerMapping 会将Controller中配置@RequestMapping注解的方法做映射存储 url 具体 控制类和方法(map=key=url ,控制类和方法)
2.BeanNameUrlHandlerMapping 根据bean标签的名称找到对应的Controller类
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /><bean id="/baanNameMayikt" class="com.mayikt.controller.BeanNameController" />
3.RouterFunctionMapping 函数式接口
1.RequestMappingHandlerMapping 会将Controller中配置@RequestMapping注解的方法做映射存储 走AbstractHandlerMethodMapping#
protected void initHandlerMethods() {for (String beanName : getCandidateBeanNames()) {if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {processCandidateBean(beanName);}}handlerMethodsInitialized(getHandlerMethods());}
2.org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping
获取注解映射url 存放在this.handlerMap.put(urlPath, resolvedHandler);
protected void detectHandlers() throws BeansException {ApplicationContext applicationContext = obtainApplicationContext();String[] beanNames = (this.detectHandlersInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :applicationContext.getBeanNamesForType(Object.class));// Take any bean name that we can determine URLs for.for (String beanName : beanNames) {String[] urls = determineUrlsForHandler(beanName);if (!ObjectUtils.isEmpty(urls)) {// URL paths found: Let's consider it a handler.registerHandler(urls, beanName);}}if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());}}
如果我们是使用@Component(“/implController”) 自定义url映射 走的
BeanNameUrlHandlerMapping
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping#lookupHandler this.handlerMap.get(urlPath); 查找对应的 控制类
如果使用@RequestMapping()
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal 查找具体url
因为springmvc支持多种url映射方式 ,每一种url映射的方式 都有自己独立的
handlerMapping 处理的方式。
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;}
查找具体HandlerMapping
根据url请求地址查找具体的HandlerMapping
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {// 循环查找对应的handlerMappingfor (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;}
注册HandlerMappings
protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);// 初始化HandlerMappingsinitHandlerMappings(context);// 初始化HandlerAdaptersinitHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}
从DispatcherServlet.properties中获取HandlerMapping
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\org.springframework.web.servlet.function.support.RouterFunctionMapping
使用反射初始化HandlerMapping 同时注册到handlerMappings 集合中。
springmvc适配器简单介绍
1.实现Controller接口方式所使用的适配器:SimpleControllerHandlerAdapter
2.实现HTTP请求处理器的适配器:HttpRequestHandlerAdapter
3.注解方式(@Controller)的处理器适配器:RequestMappingHandlerAdapter
4.实现servlet方式的适配器:SimpleServletHandlerAdapter
5.自己开发者新增适配器
方式一:@Controller/@RequestMapping
方式二:实现HttpRequestHandler接口
方式三:实现Controller接口
适配器模式就是把一个类的接口替换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
public static void invok(Controller controller) {// 判断请求url 如果是 使用Controller 该方式查找具体方法执行if (controller instanceof AnnotationController) {AnnotationController annotationController = (AnnotationController) controller;annotationController.requestMapping();return;}if (controller instanceof ImplController) {ImplController implController = (ImplController) controller;implController.handleRequest();}if (controller instanceof RequestHandlerController) {RequestHandlerController requestHandlerController = (RequestHandlerController) controller;requestHandlerController.requestHandler();}}public static void main(String[] args) {AdapterInvok.invok(new ImplController());}
}
springmvc适配器模式源码解读
获取HandlerAdapter源码解读
// 根据handler获取具体的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//根据 handler 获取对应的HandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters != null) {for (HandlerAdapter adapter : this.handlerAdapters) {//判断该handler是否是为该HandlerAdapter 是则返回//该HandlerAdapterif (adapter.supports(handler)) {return adapter;}}}throw new ServletException("No adapter for handler [" + handler +"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");}
使用实现controller接口的方式 SimpleControllerHandlerAdapter
执行我们的 handleRequest
@Component("/implController")
public class MayiktImplController implements Controller {public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {PrintWriter writer = response.getWriter();writer.print("mayikt--MayiktImplController");writer.close();return null;}
public class SimpleControllerHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return (handler instanceof Controller);}
执行// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
请求的方法
直接利用 多态机制 访问handleRequest(HttpServletRequest reques 也就是没有使用反射调用我们的方法。
使用到我们的RequestMapping(“/mayiktDemo02”)
使用org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
public final boolean supports(Object handler) {return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));}
得到bean和方法使用反射机制 调用 请求方法
protected Object doInvoke(Object... args) throws Exception {ReflectionUtils.makeAccessible(getBridgedMethod());try {return getBridgedMethod().invoke(getBean(), args);
初始化HandlerAdapter源码解读
// 初始化HandlerAdapters
protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);// 初始化HandlerAdaptersinitHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}private void initHandlerAdapters(ApplicationContext context) {this.handlerAdapters = null;if (this.detectAllHandlerAdapters) {// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.Map<String, HandlerAdapter> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerAdapters = new ArrayList<>(matchingBeans.values());// We keep HandlerAdapters in sorted order.AnnotationAwareOrderComparator.sort(this.handlerAdapters);}}else {try {HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);this.handlerAdapters = Collections.singletonList(ha);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerAdapter later.}}// Ensure we have at least some HandlerAdapters, by registering// default HandlerAdapters if no other adapters are found.if (this.handlerAdapters == null) {this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}}
使用反射机制初始化适配器模式
// Ensure we have at least some HandlerAdapters, by registering// default HandlerAdapters if no other adapters are found.if (this.handlerAdapters == null) {this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}
读取配置DispatcherServlet.properties 文件
使用java反射机制初始化适配器类
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {String key = strategyInterface.getName();//读取配置DispatcherServlet.properties 文件String value = defaultStrategies.getProperty(key);if (value != null) {String[] classNames = StringUtils.commaDelimitedListToStringArray(value);List<T> strategies = new ArrayList<>(classNames.length);for (String className : classNames) {try {//使用java反射机制初始化适配器类Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());Object strategy = createDefaultStrategy(context, clazz);strategies.add((T) strategy);}catch (ClassNotFoundException ex) {throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className +"] for interface [" + key + "]", ex);}catch (LinkageError err) {throw new BeanInitializationException("Unresolvable class definition for DispatcherServlet's default strategy class [" +className + "] for interface [" + key + "]", err);}}return strategies;}else {return new LinkedList<>();}}
根据Handler查找对应的适配器源码解读
根据Handler查找对应的适配器源码解读
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters != null) {for (HandlerAdapter adapter : this.handlerAdapters) {//根据Handler查找对应的适配器源码解读if (adapter.supports(handler)) {return adapter;}}}throw new ServletException("No adapter for handler [" + handler +"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");}
循环遍历每个适配器 判断该 handler 查找匹配对应的HandlerAdapter
1.如果是RequestMappingHandlerAdapter 则执行AbstractHandlerMethodAdapter#supports方法
注解方式(@Controller)的处理器适配器:RequestMappingHandlerAdapter
判断 return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
2.HttpRequestHandlerAdapter#supports方法
public boolean supports(Object handler) {return (handler instanceof HttpRequestHandler);}
3.SimpleControllerHandlerAdapter#supports方法
@Overridepublic boolean supports(Object handler) {return (handler instanceof Controller);}
4.SimpleServletHandlerAdapter#supports方法
public boolean supports(Object handler) {return (handler instanceof Servlet);}
执行对应的ha.handle方法
执行调用对应的ha.handle方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
执行对应适配器的handle方法
RequestMappingHandlerAdapter
如果是RequestMappingHandlerAdapter 则执行AbstractHandlerMethodAdapter#handle方法 使用java反射机制调用控制层方法
protected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ModelAndView mav;checkRequest(request);// Execute invokeHandlerMethod in synchronized block if required.if (this.synchronizeOnSession) {HttpSession session = request.getSession(false);if (session != null) {Object mutex = WebUtils.getSessionMutex(session);synchronized (mutex) {mav = invokeHandlerMethod(request, response, handlerMethod);}}else {// No HttpSession available -> no mutex necessarymav = invokeHandlerMethod(request, response, handlerMethod);}}else {// //使用java反射机制调用 方法mav = invokeHandlerMethod(request, response, handlerMethod);}if (!response.containsHeader(HEADER_CACHE_CONTROL)) {if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);}else {prepareResponse(response);}}return mav;}public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {// 拼接url上参数Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);if (logger.isTraceEnabled()) {logger.trace("Arguments: " + Arrays.toString(args));}//使用反射调用方法return doInvoke(args);}protected Object doInvoke(Object... args) throws Exception {ReflectionUtils.makeAccessible(getBridgedMethod());try {//使用反射调用方法return getBridgedMethod().invoke(getBean(), args);}
如果是RequestMappingHandlerAdapter 则执行
RequestMappingHandlerAdapter
如果是实现了controller接口,会执行SimpleControllerHandlerAdapter
#handle方法 ,执行到 controller接口对应的实现类
@Override@Nullablepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return ((Controller) handler).handleRequest(request, response);}
MayiktImplController#handleRequest
package com.mayikt.controller;import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;/**
* @author songchuanfu
* @qq 1802284273
*/
@Component("/implController")
public class MayiktImplController implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {PrintWriter writer = response.getWriter();writer.print("mayikt--MayiktImplController");writer.close();return null;}
}