Spring Web模块 关系 1 2 3 4 5 6 7 8 9 Spring Web 、Spring Web MVC 和Spring WebFlux 是Spring 框架中用于构建Web 应用程序的不同模块。它们之间的关系如下:1. Spring Web :Spring Web 是一个顶级模块,它提供了通用的Web 开发功能和抽象。它包含了一些通用的Web 特性和工具,如HTTP 请求和响应的处理、Servlet API 的封装、静态资源处理等。Spring Web 本身不提供具体的Web 框架实现,而是为其他Web 框架(如Spring Web MVC 和Spring WebFlux )提供基础支持。2. Spring Web MVC :Spring Web MVC 是基于Servlet API 的传统的Web 框架,它是Spring 框架中最早的Web 框架。它使用了经典的Servlet 和JSP 技术,通过控制器、视图解析器和模型来构建Web 应用程序。Spring Web MVC 提供了一种基于模型- 视图- 控制器(MVC )的架构模式,用于处理和响应HTTP 请求。它使用注解或XML 配置来定义请求映射、处理器方法和视图解析器等。3. Spring WebFlux :Spring WebFlux 是Spring 框架中的响应式Web 框架,它是在Spring 5 中引入的。与传统的基于Servlet 的Web 框架不同,Spring WebFlux 使用了非阻塞I / O 模型,基于Reactor 库实现了响应式编程。它提供了一种函数式和反应式的编程模型,适用于高吞吐量和低延迟的应用程序。Spring WebFlux 支持两种编程模型:基于注解的WebFlux 和基于函数式的WebFlux 。它使用路由函数来定义请求路由和处理器函数来处理请求。 总结起来,Spring Web 是一个通用的Web 开发模块,提供了基础的Web 功能和抽象。Spring Web MVC 是基于Servlet API 的传统Web 框架,使用MVC 架构模式来构建Web 应用程序。Spring WebFlux 是Spring 框架中的响应式Web 框架,使用非阻塞I / O 和响应式编程模型来构建高性能的Web 应用程序。
官方文档 Web on Servlet Stack (spring.io)
MVC容器关系图
Restful风格 idempotent : 幂等
业务 自定义全局异常处理 SpringMVC全局异常处理 - GordonDicaprio - 博客园 (cnblogs.com)
Spring Web MVC Web on Servlet Stack (spring.io)
流程 –SpringMVC执行流程:
1 2 3 4 5 6 7 8 9 10 11 01、用户发送出请求被前端控制器DispatcherServlet拦截进行处理。 02、DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。 03、HandlerMapping找到具体的处理器(查找xml配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。 04、DispatcherServlet调用HandlerAdapter(处理器适配器)。 05、HandlerAdapter经过适配调用具体的处理器(Handler/Controller)。 06、Controller执行完成返回ModelAndView对象。 07、HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。 08、DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)。 09、ViewReslover解析ModelAndView后返回具体View(视图)给DispatcherServlet。 10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。 11、DispatcherServlet响应View给用户。
–涉及组件分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1、前端控制器DispatcherServlet(不需要程序员开发)由框架提供,在web.xml中配置。 作用:接收请求,响应结果,相当于转发器,中央处理器。 2、处理器映射器HandlerMapping(不需要程序员开发)由框架提供。 作用:根据请求的url查找Handler(处理器/Controller),可以通过XML和注解方式来映射。 3、处理器适配器HandlerAdapter(不需要程序员开发)由框架提供。 作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler中的方法。 4、处理器Handler(也称之为Controller,需要程序员开发) 注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。 作用:接受用户请求信息,调用业务方法处理请求,也称之为后端控制器。 5、视图解析器ViewResolver(不需要程序员开发)由框架提供。 作用:进行视图解析,把逻辑视图解析成真正的物理视图。 SpringMVC框架支持多种View视图技术,包括:jstlView、freemarkerView、ThymeleafView等。 6、视图View(需要工程师开发) 作用:把数据展现给用户的页面 View是一个接口,实现类支持不同的View技术(jsp、freemarker、pdf等)
请求路径url-@RequestMapping 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @RequestMapping 注解在Spring Web中由RequestMappingHandlerMapping类进行解析。 RequestMappingHandlerMapping是Spring MVC框架中的一个处理器映射器(HandlerMapping),负责将请求映射到对应的处理器方法(Controller方法)。 具体的解析过程如下:1 . 组件扫描:在Spring启动时,会进行组件扫描,扫描应用程序中被@Controller 注解标记的控制器类。2 . 注册为Bean:被扫描到的@Controller 类会被实例化并注册为Spring管理的Bean。3 . 注册RequestMappingHandlerMapping:RequestMappingHandlerMapping会被自动注册到Spring MVC的上下文中。它会在Spring MVC的初始化过程中被加载,并处理请求映射。4 . 解析@RequestMapping 注解:RequestMappingHandlerMapping会扫描所有被@Controller 注解标记的类和方法,解析其中的@RequestMapping 注解。 - 类级别的@RequestMapping 注解:表示该控制器类处理的URL路径的基础路径。 - 方法级别的@RequestMapping 注解:表示该方法处理的URL路径。5 . 构建请求映射:RequestMappingHandlerMapping会根据类级别和方法级别的@RequestMapping 注解的值,构建请求映射规则。 - 类级别的@RequestMapping 注解的值会与方法级别的@RequestMapping 注解的值进行拼接,形成最终的请求路径。 - 请求路径还可以使用占位符、正则表达式等进行更灵活的匹配。6 . 注册请求映射规则:RequestMappingHandlerMapping会将解析得到的请求映射规则注册到Spring MVC的请求映射表中。 - 请求映射表是一个Map结构,将请求路径与对应的处理器方法进行映射。7 . 请求分发:当请求到达时,DispatcherServlet会调用RequestMappingHandlerMapping的方法来根据请求路径匹配最合适的处理器方法。 - RequestMappingHandlerMapping会根据请求路径在请求映射表中查找匹配的处理器方法。 - 如果找到匹配的处理器方法,就会返回对应的处理器方法。 - 如果找不到匹配的处理器方法,会返回404 错误。 总结起来,@RequestMapping 注解由RequestMappingHandlerMapping类进行解析。RequestMappingHandlerMapping会扫描被@Controller 注解标记的类和方法,解析其中的@RequestMapping 注解,并构建请求映射规则。这些规则会被注册到Spring MVC的请求映射表中,用于将请求分发给对应的处理器方法。
–根据以上分析,SpringMVC需要程序员完成的工作有三个:
【1】配置前端控制器DispatcherServlet。
RequestMappingHandlerMapping 解析 路径信息、controller到路径信息,根据路径找到合适的处理方法
【2】开发后端控制器Handler/Controller。
【3】开发视图View。
Servlet servlet详情
1 包含tomcat 的执行链:request从stream变为servletRequest的步骤吗,调用doService()前的容器执行链,wrapper 的过滤器执行
DispatcherServlet ## doService()
1 2 3 4 DispatcherServlet -> getHanlder() —> handleMapping.getHandler() -> getHandlerAdapter() ( HandlerAdapter.support()) -> preHandler() -> handlerAdapther.handler() -> postHandler()
DispatcherServlet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 public class DispatcherServlet extends FrameworkServlet { private static Properties defaultStrategies; private boolean detectAllHandlerMappings = true ; private boolean detectAllHandlerAdapters = true ; private boolean detectAllHandlerExceptionResolvers = true ; private boolean detectAllViewResolvers = true ; private boolean throwExceptionIfNoHandlerFound = false ; private boolean cleanupAfterInclude = true ; private MultipartResolver multipartResolver; private LocaleResolver localeResolver; private ThemeResolver themeResolver; private List<HandlerMapping> handlerMappings; private List<HandlerAdapter> handlerAdapters; private List<HandlerExceptionResolver> handlerExceptionResolvers; private RequestToViewNameTranslator viewNameTranslator; private FlashMapManager flashMapManager; private List<ViewResolver> viewResolvers; private boolean parseRequestPath; protected void onRefresh (ApplicationContext context) { this .initStrategies(context); } protected void initStrategies (ApplicationContext context) { this .initMultipartResolver(context); this .initLocaleResolver(context); this .initThemeResolver(context); this .initHandlerMappings(context); this .initHandlerAdapters(context); this .initHandlerExceptionResolvers(context); this .initRequestToViewNameTranslator(context); this .initViewResolvers(context); this .initFlashMapManager(context); } protected void doService (HttpServletRequest request, HttpServletResponse response) throws Exception { this .logRequest(request); Map<String, Object> attributesSnapshot = null ; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap (); Enumeration attrNames = request.getAttributeNames(); label116: while (true ) { String attrName; do { if (!attrNames.hasMoreElements()) { break label116; } attrName = (String)attrNames.nextElement(); } while (!this .cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet" )); attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this .getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this .localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this .themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, this .getThemeSource()); if (this .flashMapManager != null ) { FlashMap inputFlashMap = this .flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null ) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap ()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this .flashMapManager); } RequestPath previousRequestPath = null ; if (this .parseRequestPath) { previousRequestPath = (RequestPath)request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE); ServletRequestPathUtils.parseAndCache(request); } try { this .doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null ) { this .restoreAttributesAfterInclude(request, attributesSnapshot); } if (this .parseRequestPath) { ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request); } } } protected void doDispatch (HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null ; boolean multipartRequestParsed = false ; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { ModelAndView mv = null ; Object dispatchException = null ; try { processedRequest = this .checkMultipart(request); multipartRequestParsed = processedRequest != request; mappedHandler = this .getHandler(processedRequest); if (mappedHandler == null ) { this .noHandlerFound(processedRequest, respons e); return ; } HandlerAdapter ha = this .getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if ((new ServletWebRequest (request, response)).checkNotModified(lastModified) && isGet) { return ; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return ; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return ; } this .applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { dispatchException = new NestedServletException ("Handler dispatch failed" , err); } this .processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); catch (Exception var22) { this .triggerAfterCompletion(processedRequest, response, mappedHandler, var22); } catch (Throwable var23) { this .triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException ("Handler processing failed" , var23)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null ) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else if (multipartRequestParsed) { this .cleanupMultipart(processedRequest); } } } }
Dispathcer 注册 HandlerExceptionresolver 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 private void initHandlerExceptionResolvers (ApplicationContext context) { this .handlerExceptionResolvers = null ; if (this .detectAllHandlerExceptionResolvers) { Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true , false ); if (!matchingBeans.isEmpty()) { this .handlerExceptionResolvers = new ArrayList <>(matchingBeans.values()); AnnotationAwareOrderComparator.sort(this .handlerExceptionResolvers); } } else { try { HandlerExceptionResolver her = context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class); this .handlerExceptionResolvers = Collections.singletonList(her); } catch (NoSuchBeanDefinitionException ex) { } } if (this .handlerExceptionResolvers == null ) { this .handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class); if (logger.isTraceEnabled()) { logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() + "': using default strategies from DispatcherServlet.properties" ); } } }
Dispatcher结果处理 Dispatcher ## doDispatcher() ## processDispatchResult(). ## processHandlerException()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 private void processDispatchResult (HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false ; if (exception != null ) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered" , exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null ); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null ); } } if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isTraceEnabled()) { logger.trace("No view rendering, null ModelAndView returned." ); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { return ; } if (mappedHandler != null ) { mappedHandler.triggerAfterCompletion(request, response, null ); } }@Nullable protected ModelAndView processHandlerException (HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception { request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); ModelAndView exMv = null ; if (this .handlerExceptionResolvers != null ) { for (HandlerExceptionResolver resolver : this .handlerExceptionResolvers) { exMv = resolver.resolveException(request, response, handler, ex); if (exMv != null ) { break ; } } } if (exMv != null ) { if (exMv.isEmpty()) { request.setAttribute(EXCEPTION_ATTRIBUTE, ex); return null ; } if (!exMv.hasView()) { String defaultViewName = getDefaultViewName(request); if (defaultViewName != null ) { exMv.setViewName(defaultViewName); } } if (logger.isTraceEnabled()) { logger.trace("Using resolved error view: " + exMv, ex); } else if (logger.isDebugEnabled()) { logger.debug("Using resolved error view: " + exMv); } WebUtils.exposeErrorRequestAttributes(request, ex, getServletName()); return exMv; } throw ex; }
HandlerExceptionResolver 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public interface HandlerExceptionResolver { @Nullable ModelAndView resolveException ( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) ; }
HandlerMapping 1 2 3 4 5 6 7 8 9 public interface HandlerMapping { String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler" ; default boolean usesPathPatterns () { return false ; } HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception; }
HandlerExecutionChain 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class HandlerExecutionChain { private final Object handler; private final List<HandlerInterceptor> interceptorList; private int interceptorIndex; boolean applyPreHandle (HttpServletRequest request, HttpServletResponse response) throws Exception { for (int i = 0 ; i < this .interceptorList.size(); this .interceptorIndex = i++) { HandlerInterceptor interceptor = (HandlerInterceptor)this .interceptorList.get(i); if (!interceptor.preHandle(request, response, this .handler)) { this .triggerAfterCompletion(request, response, (Exception)null ); return false ; } } return true ; } void applyPostHandle (HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { for (int i = this .interceptorList.size() - 1 ; i >= 0 ; --i) { HandlerInterceptor interceptor = (HandlerInterceptor)this .interceptorList.get(i); interceptor.postHandle(request, response, this .handler, mv); } } void triggerAfterCompletion (HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) { for (int i = this .interceptorIndex; i >= 0 ; --i) { HandlerInterceptor interceptor = (HandlerInterceptor)this .interceptorList.get(i); try { interceptor.afterCompletion(request, response, this .handler, ex); } catch (Throwable var7) { logger.error("HandlerInterceptor.afterCompletion threw exception" , var7); } } } public Object getHandler () { return this .handler; } }
HandlerInterceptor 拦截器执行链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public interface HandlerInterceptor { default boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true ; } default void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
AsyncHandlerInterceptor 1 2 3 4 5 public interface AsyncHandlerInterceptor extends HandlerInterceptor { default void afterConcurrentHandlingStarted (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { } }
**DispatcherServlet ## doDispatcher() **
## HandlerAdapther.handler()
1 2 3 4 5 6 7 8 9 10 11 HandlerAdapter AbstractHandlerMethodAdapter RequestMappingHandlerAdapter ServletInvocableHandlerMethod HandlerMethodReturnValueHandlerComposite HandlerMethodReturnValueHandler
HandlerAdapter 1 2 3 4 5 6 7 8 9 10 public interface HandlerAdapter { boolean supports (Object handler) ; @Nullable ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; @Deprecated long getLastModified (HttpServletRequest request, Object handler) ; }
AbstractHandlerMethodAdapter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter , Ordered { private int order = 2147483647 ; public void setOrder (int order) { this .order = order; } public final boolean supports (Object handler) { return handler instanceof HandlerMethod && this .supportsInternal((HandlerMethod)handler); } protected abstract boolean supportsInternal (HandlerMethod handlerMethod) ; public final ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return this .handleInternal(request, response, (HandlerMethod)handler); } protected abstract ModelAndView handleInternal (HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
RequestMappingHandlerAdapter 参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware , InitializingBean { private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore" ); public static final MethodFilter INIT_BINDER_METHODS = (method) -> { return AnnotatedElementUtils.hasAnnotation(method, InitBinder.class); }; public static final MethodFilter MODEL_ATTRIBUTE_METHODS = (method) -> { return !AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) && AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class); }; private List<HandlerMethodArgumentResolver> customArgumentResolvers; private HandlerMethodArgumentResolverComposite argumentResolvers; private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers; private List<HandlerMethodReturnValueHandler> customReturnValueHandlers; private HandlerMethodReturnValueHandlerComposite returnValueHandlers; private List<ModelAndViewResolver> modelAndViewResolvers; private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager (); private List<HttpMessageConverter<?>> messageConverters = new ArrayList (4 ); private final List<Object> requestResponseBodyAdvice = new ArrayList (); private WebBindingInitializer webBindingInitializer; private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor ("MvcAsync" ); private Long asyncRequestTimeout; private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor [0 ]; private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor [0 ]; private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); private boolean ignoreDefaultModelOnRedirect = false ; private int cacheSecondsForSessionAttributeHandlers = 0 ; private boolean synchronizeOnSession = false ; private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore (); private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer (); @Nullable private ConfigurableBeanFactory beanFactory; private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap (64 ); private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap (64 ); private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap (); private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap (64 ); private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap ();
初始化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 public void afterPropertiesSet () { this .initControllerAdviceCache(); List handlers; if (this .argumentResolvers == null ) { handlers = this .getDefaultArgumentResolvers(); this .argumentResolvers = (new HandlerMethodArgumentResolverComposite ()).addResolvers(handlers); } if (this .initBinderArgumentResolvers == null ) { handlers = this .getDefaultInitBinderArgumentResolvers(); this .initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite ()).addResolvers(handlers); } if (this .returnValueHandlers == null ) { handlers = this .getDefaultReturnValueHandlers(); this .returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite ()).addHandlers(handlers); } } public static final MethodFilter INIT_BINDER_METHODS = (method) -> { return AnnotatedElementUtils.hasAnnotation(method, InitBinder.class); };public static final MethodFilter MODEL_ATTRIBUTE_METHODS = (method) -> { return !AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) && AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class); }; private void initControllerAdviceCache () { if (this .getApplicationContext() != null ) { List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(this .getApplicationContext()); List<Object> requestResponseBodyAdviceBeans = new ArrayList (); Iterator var3 = adviceBeans.iterator(); while (var3.hasNext()) { ControllerAdviceBean adviceBean = (ControllerAdviceBean)var3.next(); Class<?> beanType = adviceBean.getBeanType(); if (beanType == null ) { throw new IllegalStateException ("Unresolvable type for ControllerAdviceBean: " + adviceBean); } Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { this .modelAttributeAdviceCache.put(adviceBean, attrMethods); } Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this .initBinderAdviceCache.put(adviceBean, binderMethods); } if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) { requestResponseBodyAdviceBeans.add(adviceBean); } } if (!requestResponseBodyAdviceBeans.isEmpty()) { this .requestResponseBodyAdvice.addAll(0 , requestResponseBodyAdviceBeans); } } }
RequestBodyAdvice 1 2 3 4 5 6 7 8 9 10 public interface RequestBodyAdvice { boolean supports (MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) ; HttpInputMessage beforeBodyRead (HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException; Object afterBodyRead (Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) ; @Nullable Object handleEmptyBody (@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) ; }
handleInternal 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 protected ModelAndView handleInternal (HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { this .checkRequest(request); ModelAndView mav; if (this .synchronizeOnSession) { HttpSession session = request.getSession(false ); if (session != null ) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { mav = this .invokeHandlerMethod(request, response, handlerMethod); } } else { mav = this .invokeHandlerMethod(request, response, handlerMethod); } } else { mav = this .invokeHandlerMethod(request, response, handlerMethod); } if (!response.containsHeader("Cache-Control" )) { if (this .getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { this .applyCacheSeconds(response, this .cacheSecondsForSessionAttributeHandlers); } else { this .prepareResponse(response); } } return mav; } protected ModelAndView invokeHandlerMethod (HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest (request, response); ModelAndView var15; try { WebDataBinderFactory binderFactory = this .getDataBinderFactory(handlerMethod); ModelFactory modelFactory = this .getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = this .createInvocableHandlerMethod(handlerMethod); if (this .argumentResolvers != null ) { invocableMethod.setHandlerMethodArgumentResolvers(this .argumentResolvers); } if (this .returnValueHandlers != null ) { invocableMethod.setHandlerMethodReturnValueHandlers(this .returnValueHandlers); } invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this .parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer (); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this .ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this .asyncRequestTimeout); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this .taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this .callableInterceptors); asyncManager.registerDeferredResultInterceptors(this .deferredResultInterceptors); Object result; if (asyncManager.hasConcurrentResult()) { result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0 ]; asyncManager.clearConcurrentResult(); LogFormatUtils.traceDebug(this .logger, (traceOn) -> { String formatted = LogFormatUtils.formatValue(result, !traceOn); return "Resume with async result [" + formatted + "]" ; }); invocableMethod = invocableMethod.wrapConcurrentResult(result); } invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object [0 ]); if (asyncManager.isConcurrentHandlingStarted()) { result = null ; return (ModelAndView)result; } var15 = this .getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } return var15; } }
GlobalControllerAdvice ExceptionHandlerExceptionResolver getModelFactory 1 2 3 ModelFactory InvocableHandlerMethod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private ModelFactory getModelFactory (HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) { SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod); Class<?> handlerType = handlerMethod.getBeanType(); Set<Method> methods = this .modelAttributeCache.get(handlerType); if (methods == null ) { methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS); this .modelAttributeCache.put(handlerType, methods); } List<InvocableHandlerMethod> attrMethods = new ArrayList <>(); this .modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> { if (controllerAdviceBean.isApplicableToBeanType(handlerType)) { Object bean = controllerAdviceBean.resolveBean(); for (Method method : methodSet) { attrMethods.add(createModelAttributeMethod(binderFactory, bean, method)); } } }); for (Method method : methods) { Object bean = handlerMethod.getBean(); attrMethods.add(createModelAttributeMethod(binderFactory, bean, method)); } return new ModelFactory (attrMethods, binderFactory, sessionAttrHandler); }
HandlerMethod 方法执行,封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class HandlerMethod { protected static final Log logger = LogFactory.getLog(HandlerMethod.class); private final Object bean; @Nullable private final BeanFactory beanFactory; @Nullable private final MessageSource messageSource; private final Class<?> beanType; private final Method method; private final Method bridgedMethod; private final MethodParameter[] parameters; @Nullable private HttpStatus responseStatus; @Nullable private String responseStatusReason; @Nullable private HandlerMethod resolvedFromHandlerMethod; @Nullable private volatile List<Annotation[][]> interfaceParameterAnnotations; private final String description; private class ReturnValueMethodParameter extends HandlerMethod .HandlerMethodParameter { @Nullable private final Class<?> returnValueType; } protected class HandlerMethodParameter extends SynthesizingMethodParameter { @Nullable private volatile Annotation[] combinedAnnotations; } }
ServletInvocableHandlerMethod 是对InvocableHandlerMethod的增强,能够处理返回值,将返回值写入Response,而不是返回ModelAndView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call" , new Class [0 ]); @Nullable private HandlerMethodReturnValueHandlerComposite returnValueHandlers; public void invokeAndHandle (ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = this .invokeForRequest(webRequest, mavContainer, providedArgs); this .setResponseStatus(webRequest); if (returnValue == null ) { if (this .isRequestNotModified(webRequest) || this .getResponseStatus() != null || mavContainer.isRequestHandled()) { this .disableContentCachingIfNecessary(webRequest); mavContainer.setRequestHandled(true ); return ; } } else if (StringUtils.hasText(this .getResponseStatusReason())) { mavContainer.setRequestHandled(true ); return ; } mavContainer.setRequestHandled(false ); Assert.state(this .returnValueHandlers != null , "No return value handlers" ); try { this .returnValueHandlers.handleReturnValue(returnValue, this .getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception var6) { if (logger.isTraceEnabled()) { logger.trace(this .formatErrorForReturnValue(returnValue), var6); } throw var6; } } }
InvocableHandlerMethod 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class InvocableHandlerMethod extends HandlerMethod { private static final Object[] EMPTY_ARGS = new Object [0 ]; private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite (); private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer (); @Nullable private WebDataBinderFactory dataBinderFactory; public Object invokeForRequest (NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object[] args = this .getMethodArgumentValues(request, mavContainer, providedArgs); return this .doInvoke(args); } protected Object doInvoke (Object... args) throws Exception { Method method = this .getBridgedMethod(); try { return KotlinDetector.isSuspendingFunction(method) ? CoroutinesUtils.invokeSuspendingFunction(method, this .getBean(), args) : method.invoke(this .getBean(), args); } } }
MethodParameter 封装 方法参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class MethodParameter { private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation [0 ]; private final Executable executable; private final int parameterIndex; @Nullable private volatile Parameter parameter; private int nestingLevel; @Nullable Map<Integer, Integer> typeIndexesPerLevel; @Nullable private volatile Class<?> containingClass; @Nullable private volatile Class<?> parameterType; @Nullable private volatile Type genericParameterType; @Nullable private volatile Annotation[] parameterAnnotations; @Nullable private volatile ParameterNameDiscoverer parameterNameDiscoverer; @Nullable private volatile String parameterName; @Nullable private volatile MethodParameter nestedMethodParameter;
HandlerMethodReturnValueHandler 用于处理方法返回值的 Hanlder
1 2 3 4 5 6 public interface HandlerMethodReturnValueHandler { boolean supportsReturnType (MethodParameter returnType) ; void handleReturnValue (@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; }
HandlerMethodReturnValueHandlerComposite 相当于抽象类的实现,用于转发 当前的方法到具体实现
1 2 3 4 public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler { private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList (); }
ResponseBodyEmitterReturnValueHandler 将返回值写入 返回体中
1 2 3 4 public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler { private final List<HttpMessageConverter<?>> sseMessageConverters; private final ReactiveTypeHandler reactiveHandler; }
HandlerExceptionResolver 异常处理解析
1 2 3 4 public interface HandlerExceptionResolver { @Nullable ModelAndView resolveException (HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) ; }
ExceptionHandlerExceptionResolver 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver implements ApplicationContextAware , InitializingBean { private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore" ); @Nullable private List<HandlerMethodArgumentResolver> customArgumentResolvers; @Nullable private HandlerMethodArgumentResolverComposite argumentResolvers; @Nullable private List<HandlerMethodReturnValueHandler> customReturnValueHandlers; @Nullable private HandlerMethodReturnValueHandlerComposite returnValueHandlers; private List<HttpMessageConverter<?>> messageConverters = new ArrayList (); private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager (); private final List<Object> responseBodyAdvice = new ArrayList (); @Nullable private ApplicationContext applicationContext; private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache = new ConcurrentHashMap (64 ); private final Map<ControllerAdviceBean, ExceptionHandlerMethodResolver> exceptionHandlerAdviceCache = new LinkedHashMap (); static { try { NO_MATCHING_EXCEPTION_HANDLER_METHOD = ExceptionHandlerMethodResolver.class.getDeclaredMethod("noMatchingExceptionHandler" ); } catch (NoSuchMethodException var1) { throw new IllegalStateException ("Expected method not found: " + var1); } } private void noMatchingExceptionHandler () { } public void afterPropertiesSet () { this .initExceptionHandlerAdviceCache(); List handlers; if (this .argumentResolvers == null ) { handlers = this .getDefaultArgumentResolvers(); this .argumentResolvers = (new HandlerMethodArgumentResolverComposite ()).addResolvers(handlers); } if (this .returnValueHandlers == null ) { handlers = this .getDefaultReturnValueHandlers(); this .returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite ()).addHandlers(handlers); } } private void initExceptionHandlerAdviceCache () { if (this .getApplicationContext() != null ) { List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(this .getApplicationContext()); Iterator var2 = adviceBeans.iterator(); while (var2.hasNext()) { ControllerAdviceBean adviceBean = (ControllerAdviceBean)var2.next(); Class<?> beanType = adviceBean.getBeanType(); ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver (beanType); if (resolver.hasExceptionMappings()) { this .exceptionHandlerAdviceCache.put(adviceBean, resolver); } if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) { this .responseBodyAdvice.add(adviceBean); } } if (this .logger.isDebugEnabled()) { int handlerSize = this .exceptionHandlerAdviceCache.size(); int adviceSize = this .responseBodyAdvice.size(); } } } }
ExceptionHandlerMethodResolver @ExceptionHandler的异常处理方法的解析 和 缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class ExceptionHandlerMethodResolver { public static final MethodFilter EXCEPTION_HANDLER_METHODS = (method) -> { return AnnotatedElementUtils.hasAnnotation(method, ExceptionHandler.class); }; private static final Method NO_MATCHING_EXCEPTION_HANDLER_METHOD; private final Map<Class<? extends Throwable >, Method> mappedMethods = new HashMap (16 ); private final Map<Class<? extends Throwable >, Method> exceptionLookupCache = new ConcurrentReferenceHashMap (16 ); public ExceptionHandlerMethodResolver (Class<?> handlerType) { Iterator var2 = MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS).iterator(); while (var2.hasNext()) { Method method = (Method)var2.next(); Iterator var4 = this .detectExceptionMappings(method).iterator(); while (var4.hasNext()) { Class<? extends Throwable > exceptionType = (Class)var4.next(); this .addExceptionMapping(exceptionType, method); } } } }public final class MethodIntrospector { public static Set<Method> selectMethods (Class<?> targetType, MethodFilter methodFilter) { return selectMethods(targetType, (method) -> { return methodFilter.matches(method) ? Boolean.TRUE : null ; }).keySet(); } }
@Exception 注册 ExceptionHandlerExceptionResolver 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver implements ApplicationContextAware , InitializingBean { @Override public void afterPropertiesSet () { initExceptionHandlerAdviceCache(); if (this .argumentResolvers == null ) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this .argumentResolvers = new HandlerMethodArgumentResolverComposite ().addResolvers(resolvers); } if (this .returnValueHandlers == null ) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this .returnValueHandlers = new HandlerMethodReturnValueHandlerComposite ().addHandlers(handlers); } } private void initExceptionHandlerAdviceCache () { if (getApplicationContext() == null ) { return ; } List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); for (ControllerAdviceBean adviceBean : adviceBeans) { Class<?> beanType = adviceBean.getBeanType(); if (beanType == null ) { throw new IllegalStateException ("Unresolvable type for ControllerAdviceBean: " + adviceBean); } ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver (beanType); if (resolver.hasExceptionMappings()) { this .exceptionHandlerAdviceCache.put(adviceBean, resolver); } if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) { this .responseBodyAdvice.add(adviceBean); } } if (logger.isDebugEnabled()) { int handlerSize = this .exceptionHandlerAdviceCache.size(); int adviceSize = this .responseBodyAdvice.size(); if (handlerSize == 0 && adviceSize == 0 ) { logger.debug("ControllerAdvice beans: none" ); } else { logger.debug("ControllerAdvice beans: " + handlerSize + " @ExceptionHandler, " + adviceSize + " ResponseBodyAdvice" ); } } } }
ExceptionHandlerMethodResolver 解析 异常@ExceptionHandler 注解的方法。=== 该注解必须配合@ControllerAdvice 使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public class ExceptionHandlerMethodResolver { public static final MethodFilter EXCEPTION_HANDLER_METHODS = method -> AnnotatedElementUtils.hasAnnotation(method, ExceptionHandler.class); private static final Method NO_MATCHING_EXCEPTION_HANDLER_METHOD; public ExceptionHandlerMethodResolver (Class<?> handlerType) { for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) { for (Class<? extends Throwable > exceptionType : detectExceptionMappings(method)) { addExceptionMapping(exceptionType, method); } } } @SuppressWarnings("unchecked") private List<Class<? extends Throwable >> detectExceptionMappings(Method method) { List<Class<? extends Throwable >> result = new ArrayList <>(); detectAnnotationExceptionMappings(method, result); if (result.isEmpty()) { for (Class<?> paramType : method.getParameterTypes()) { if (Throwable.class.isAssignableFrom(paramType)) { result.add((Class<? extends Throwable >) paramType); } } } if (result.isEmpty()) { throw new IllegalStateException ("No exception types mapped to " + method); } return result; } private void detectAnnotationExceptionMappings (Method method, List<Class<? extends Throwable>> result) { ExceptionHandler ann = AnnotatedElementUtils.findMergedAnnotation(method, ExceptionHandler.class); Assert.state(ann != null , "No ExceptionHandler annotation" ); result.addAll(Arrays.asList(ann.value())); } private void addExceptionMapping (Class<? extends Throwable> exceptionType, Method method) { Method oldMethod = this .mappedMethods.put(exceptionType, method); if (oldMethod != null && !oldMethod.equals(method)) { throw new IllegalStateException ("Ambiguous @ExceptionHandler method mapped for [" + exceptionType + "]: {" + oldMethod + ", " + method + "}" ); } } }
Advice ControllerAdviceBean @ControllerAdvice注解所在Bean的信息封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class ControllerAdviceBean implements Ordered { private final Object beanOrName; private final boolean isSingleton; private Object resolvedBean; private final Class<?> beanType; private final HandlerTypePredicate beanTypePredicate; @Nullable private final BeanFactory beanFactory; @Nullable private Integer order; public static List<ControllerAdviceBean> findAnnotatedBeans (ApplicationContext context) { ListableBeanFactory beanFactory = context; if (context instanceof ConfigurableApplicationContext) { beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory(); } List<ControllerAdviceBean> adviceBeans = new ArrayList (); String[] var3 = BeanFactoryUtils.beanNamesForTypeIncludingAncestors((ListableBeanFactory)beanFactory, Object.class); int var4 = var3.length; for (int var5 = 0 ; var5 < var4; ++var5) { String name = var3[var5]; if (!ScopedProxyUtils.isScopedTarget(name)) { ControllerAdvice controllerAdvice = (ControllerAdvice) ((ListableBeanFactory)beanFactory).findAnnotationOnBean(name, ControllerAdvice.class); if (controllerAdvice != null ) { adviceBeans.add(new ControllerAdviceBean (name, (BeanFactory)beanFactory, controllerAdvice)); } } } OrderComparator.sort(adviceBeans); return adviceBeans; } public ControllerAdviceBean (String beanName, BeanFactory beanFactory, @Nullable ControllerAdvice controllerAdvice) { this .beanOrName = beanName; this .isSingleton = beanFactory.isSingleton(beanName); this .beanType = getBeanType(beanName, beanFactory); this .beanTypePredicate = controllerAdvice != null ? createBeanTypePredicate(controllerAdvice) : createBeanTypePredicate(this .beanType); this .beanFactory = beanFactory; } private static HandlerTypePredicate createBeanTypePredicate (@Nullable ControllerAdvice controllerAdvice) { return controllerAdvice != null ? HandlerTypePredicate.builder().basePackage(controllerAdvice.basePackages()).basePackageClass(controllerAdvice.basePackageClasses()).assignableType(controllerAdvice.assignableTypes()).annotation(controllerAdvice.annotations()).build() : HandlerTypePredicate.forAnyHandlerType(); } }
HandlerTypePredicate 取出注解的属性信息,封装为类方便调用
1 2 3 4 5 6 7 8 public final class HandlerTypePredicate implements Predicate <Class<?>> { private final Set<String> basePackages; private final List<Class<?>> assignableTypes; private final List<Class<? extends Annotation >> annotations; }
ControllerAdvice 来自@ControllerAdvice的全局@ExceptionHandler方法在@Controller的本地方法之后应用。相比之下,全局的@ModelAttribute和@InitBinder方法在局部方法之前应用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface ControllerAdvice { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<?>[] assignableTypes() default {}; Class<? extends Annotation >[] annotations() default {}; }@ControllerAdvice(annotations = RestController.class) public class ExampleAdvice1 {}@ControllerAdvice("org.example.controllers") public class ExampleAdvice2 {}@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class}) public class ExampleAdvice3 {}
@InitBinder @ModelAttribute RequestBodyAdvice
@ExceptionHandler ExceptionHandlerMethodResolver
RequestBodyAdvice 1 2 3 4 5 6 7 8 9 10 public interface RequestBodyAdvice { boolean supports (MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) ; HttpInputMessage beforeBodyRead (HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException; Object afterBodyRead (Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) ; @Nullable Object handleEmptyBody (@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) ; }
ResponseBodyAdvice 1 2 3 4 5 6 public interface ResponseBodyAdvice <T> { boolean supports (MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) ; @Nullable T beforeBodyWrite (@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) ; }
其他参数 ModelAndView 1 2 3 4 5 6 7 8 9 public class ModelAndView { @Nullable private Object view; @Nullable private ModelMap model; @Nullable private HttpStatus status; private boolean cleared = false ; }
Model 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public interface Model { Model addAttribute (String var1, @Nullable Object var2) ; Model addAttribute (Object var1) ; Model addAllAttributes (Collection<?> var1) ; Model addAllAttributes (Map<String, ?> var1) ; Model mergeAttributes (Map<String, ?> var1) ; boolean containsAttribute (String var1) ; @Nullable Object getAttribute (String var1) ; Map<String, Object> asMap () ; }
RedirectAttributes 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface RedirectAttributes extends Model { RedirectAttributes addAttribute (String attributeName, @Nullable Object attributeValue) ; RedirectAttributes addAttribute (Object attributeValue) ; RedirectAttributes addAllAttributes (Collection<?> attributeValues) ; RedirectAttributes mergeAttributes (Map<String, ?> attributes) ; RedirectAttributes addFlashAttribute (String attributeName, @Nullable Object attributeValue) ; RedirectAttributes addFlashAttribute (Object attributeValue) ; Map<String, ?> getFlashAttributes(); }
HtttpMessage 1 2 3 public interface HttpMessage { HttpHeaders getHeaders () ; }
1 2 3 public interface HttpInputMessage extends HttpMessage { InputStream getBody () throws IOException; }
HttpRequest 1 2 3 4 5 6 7 8 9 10 public interface HttpRequest extends HttpMessage { @Nullable default HttpMethod getMethod () { return HttpMethod.resolve(this .getMethodValue()); } String getMethodValue () ; URI getURI () ; }
ServerHttpRequest 1 2 3 4 5 6 7 8 9 10 public interface ServerHttpRequest extends HttpRequest , HttpInputMessage { @Nullable Principal getPrincipal () ; InetSocketAddress getLocalAddress () ; InetSocketAddress getRemoteAddress () ; ServerHttpAsyncRequestControl getAsyncRequestControl (ServerHttpResponse response) ; }
ServletServerHttpRequest — 具体实现
HttpOutputMessage 1 2 3 public interface HttpOutputMessage extends HttpMessage { OutputStream getBody () throws IOException; }
ServerHttpResponse 1 2 3 4 5 6 7 public interface ServerHttpResponse extends HttpOutputMessage , Flushable, Closeable { void setStatusCode (HttpStatus status) ; void flush () throws IOException; void close () ; }
ServletServerHttpResponse – 具体实现
HttpSession Tomcat Session — Tomcat
StandardSessionFacade — Tomcat
StandardSession – Tomcat
Spring Session Session – Spring Session
HttpSessionAdapter – Spring Session (分布式session)
Spring WebFlux Web on Reactive Stack (spring.io)
WebFlux Spring Boot整合 Spring Web MVC 1 2 3 SpringApplication ## context = this .createApplicationContext();
SpringApplication ## run () ## createApplicationContext 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 protected ConfigurableApplicationContext createApplicationContext () { Class<?> contextClass = this .applicationContextClass; if (contextClass == null ) { try { switch (this .webApplicationType) { case SERVLET: contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext" ); break ; case REACTIVE: contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext" ); break ; default : contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext" ); } } catch (ClassNotFoundException var3) { throw new IllegalStateException ("Unable create a default ApplicationContext, please specify an ApplicationContextClass" , var3); } } return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass); }
AnnotationConfigServletWebServerApplicationContext 父类 : ServletWebServerApplicationContext -> GenericWebApplicationContext ## onRefresh()
run() ## refresh()
ServletWebServerApplicationContext ## onRefresh() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext { private static final Log logger = LogFactory.getLog(ServletWebServerApplicationContext.class); public static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet" ; private volatile WebServer webServer; private ServletConfig servletConfig; private String serverNamespace; protected void onRefresh () { super .onRefresh(); this .createWebServer(); } private void createWebServer () { WebServer webServer = this .webServer; ServletContext servletContext = this .getServletContext(); if (webServer == null && servletContext == null ) { ServletWebServerFactory factory = this .getWebServerFactory(); this .webServer = factory.getWebServer(new ServletContextInitializer []{this .getSelfInitializer()}); this .getBeanFactory().registerSingleton("webServerGracefulShutdown" , new WebServerGracefulShutdownLifecycle (this .webServer)); this .getBeanFactory().registerSingleton("webServerStartStop" , new WebServerStartStopLifecycle (this , this .webServer)); } else if (servletContext != null ) { try { this .getSelfInitializer().onStartup(servletContext); } catch (ServletException var4) { throw new ApplicationContextException ("Cannot initialize servlet context" , var4); } } this .initPropertySources(); } }
ServletContextInitializer 1 2 3 4 @FunctionalInterface public interface ServletContextInitializer { void onStartup (ServletContext servletContext) throws ServletException; }
GenericWebApplicationContext ## initPropertySources 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class GenericWebApplicationContext extends GenericApplicationContext implements ConfigurableWebApplicationContext , ThemeSource { @Nullable private ServletContext servletContext; @Nullable private ThemeSource themeSource; protected void initPropertySources () { ConfigurableEnvironment env = this .getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment)env).initPropertySources(this .servletContext, (ServletConfig)null ); } } }
ConfigurableWebEnvironment 关键类:StandardServletEnvironment
对于PropertySource还不熟
1 2 3 public interface ConfigurableWebEnvironment extends ConfigurableEnvironment { void initPropertySources (@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) ; }
StandardServletEnvironment 1 2 3 4 5 6 7 8 9 10 public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment { public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams" ; public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams" ; public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties" ; private static final boolean jndiPresent = ClassUtils.isPresent("javax.naming.InitialContext" , StandardServletEnvironment.class.getClassLoader()); public void initPropertySources (@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) { WebApplicationContextUtils.initServletPropertySources(this .getPropertySources(), servletContext, servletConfig); } }