注册到容器

springboot在启动的时候,加载配置类
WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter
向容器注册了

  1. @Bean
  2. @Primary
  3. @Override
  4. public RequestMappingHandlerMapping requestMappingHandlerMapping(
  5. @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
  6. @Qualifier("mvcConversionService") FormattingConversionService conversionService,
  7. @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
  8. // Must be @Primary for MvcUriComponentsBuilder to work
  9. return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
  10. resourceUrlProvider);
  11. }

真正的方法在父类

  1. @Bean
  2. @SuppressWarnings("deprecation")
  3. public RequestMappingHandlerMapping requestMappingHandlerMapping(
  4. @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
  5. @Qualifier("mvcConversionService") FormattingConversionService conversionService,
  6. @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
  7. RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
  8. mapping.setOrder(0);
  9. //设置了拦截器
  10. mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
  11. mapping.setContentNegotiationManager(contentNegotiationManager);
  12. mapping.setCorsConfigurations(getCorsConfigurations());
  13. PathMatchConfigurer pathConfig = getPathMatchConfigurer();
  14. if (pathConfig.getPatternParser() != null) {
  15. mapping.setPatternParser(pathConfig.getPatternParser());
  16. }
  17. else {
  18. mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
  19. mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
  20. Boolean useSuffixPatternMatch = pathConfig.isUseSuffixPatternMatch();
  21. if (useSuffixPatternMatch != null) {
  22. mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
  23. }
  24. Boolean useRegisteredSuffixPatternMatch = pathConfig.isUseRegisteredSuffixPatternMatch();
  25. if (useRegisteredSuffixPatternMatch != null) {
  26. mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
  27. }
  28. }
  29. Boolean useTrailingSlashMatch = pathConfig.isUseTrailingSlashMatch();
  30. if (useTrailingSlashMatch != null) {
  31. mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
  32. }
  33. if (pathConfig.getPathPrefixes() != null) {
  34. mapping.setPathPrefixes(pathConfig.getPathPrefixes());
  35. }
  36. return mapping;
  37. }

调用了同类的getInterceptors方法,跟进去

  1. /**
  2. * Provide access to the shared handler interceptors used to configure
  3. * {@link HandlerMapping} instances with.
  4. * <p>This method cannot be overridden; use {@link #addInterceptors} instead.
  5. */
  6. protected final Object[] getInterceptors(
  7. FormattingConversionService mvcConversionService,
  8. ResourceUrlProvider mvcResourceUrlProvider) {
  9. if (this.interceptors == null) {
  10. InterceptorRegistry registry = new InterceptorRegistry();
  11. addInterceptors(registry);
  12. registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
  13. registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
  14. this.interceptors = registry.getInterceptors();
  15. }
  16. return this.interceptors.toArray();
  17. }

有2个默认的拦截器是springboot帮我们new好的;自定义拦截器是通过方法addInterceptors(registry)添加进去的,继续跟

  1. #DelegatingWebMvcConfiguration#
  2. @Override
  3. protected void addInterceptors(InterceptorRegistry registry) {
  4. this.configurers.addInterceptors(registry);
  5. }
  6. #WebMvcConfigurerComposite#
  7. private final List<WebMvcConfigurer> delegates = new ArrayList<>();
  8. @Override
  9. public void addInterceptors(InterceptorRegistry registry) {
  10. for (WebMvcConfigurer delegate : this.delegates) {
  11. delegate.addInterceptors(registry);
  12. }
  13. }

这里的delegates包括:

  1. springboot帮我们配置好的
    1. WebMvcAutoConfiguration里面的静态内部配置类WebMvcAutoConfigurationAdapter implements WebMvcConfigurer
  2. 我们自己去实现这个接口的配置类,可以有多个噢

    1. @Configuration
    2. public class AdminWebConfig implements WebMvcConfigurer {
    3. @Override
    4. public void addInterceptors(InterceptorRegistry registry) {
    5. registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/login", "/");
    6. }
    7. }

    嵌入流程

    请求所有的入口都是DispatcherServlet#doDispatch
    三个方法preHandle;postHandle;afterCompletion

    1. @Slf4j
    2. public class MyInterceptor implements HandlerInterceptor {
    3. @Override
    4. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    5. String requestURI = request.getRequestURI();
    6. log.info("preHandle拦截的请求路径是{}",requestURI);
    7. //登录检查逻辑
    8. HttpSession session = request.getSession();
    9. Object loginUser = session.getAttribute("loginUser");
    10. if(loginUser != null)
    11. return true;
    12. request.setAttribute("msg","请先登录");//拦截住。未登录。跳转到登录页
    13. request.getRequestDispatcher("/").forward(request,response);
    14. return false;
    15. }
    16. @Override
    17. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    18. }
    19. @Override
    20. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    21. }
    22. }

    执行的在哪里呢 ```java

    DispatcherServlet

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

    1. HttpServletRequest processedRequest = request;
    2. HandlerExecutionChain mappedHandler = null;
    3. boolean multipartRequestParsed = false;
  1. try {
  2. ModelAndView mv = null;
  3. Exception dispatchException = null;
  4. try {
  5. processedRequest = checkMultipart(request);
  6. multipartRequestParsed = (processedRequest != request);
  7. // Determine handler for the current request.
  8. 【把注册的拦截器看看是否匹配,然后放在HandlerExecutionChain里面】
  9. mappedHandler = getHandler(processedRequest);
  10. ......代码省略
  11. // Determine handler adapter for the current request.
  12. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  13. ......代码省略
  14. 【详见下面具体的源码,执行前置处理】
  15. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  16. return;
  17. }
  18. // Actually invoke the handler.
  19. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  20. ......代码省略
  21. 【详见下面具体的源码,执行后置处理】
  22. mappedHandler.applyPostHandle(processedRequest, response, mv);
  23. }
  24. catch (Exception ex) {
  25. dispatchException = ex;
  26. }
  27. catch (Throwable err) {
  28. // As of 4.3, we're processing Errors thrown from handler methods as well,
  29. // making them available for @ExceptionHandler methods and other scenarios.
  30. dispatchException = new NestedServletException("Handler dispatch failed", err);
  31. }
  32. //里面调用了mappedHandler.triggerAfterCompletion(request, response, null);
  33. 、、【详见下面具体的源码,执行完成处理】
  34. processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  35. }
  36. catch (Exception ex) {
  37. 【详见下面具体的源码,执行完成处理】
  38. triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  39. }
  40. catch (Throwable err) {
  41. 【详见下面具体的源码,执行完成处理】
  42. triggerAfterCompletion(processedRequest, response, mappedHandler,
  43. new NestedServletException("Handler processing failed", err));
  44. }
  45. finally {
  46. ......代码省略
  47. }
  48. }

//1.得到请求处理,2.并且也得到对应的拦截器 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; }

  1. ```java
  2. #RequestMappingInfoHandlerMapping
  3. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  4. Object handler = getHandlerInternal(request); //1.得到请求处理,匹配请求url
  5. HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);//2.并且也得到对应的拦截器
  6. return executionChain;
  7. }
  8. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
  9. HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
  10. (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
  11. for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
  12. if (interceptor instanceof MappedInterceptor) {
  13. MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
  14. 【匹配了就加进去】
  15. if (mappedInterceptor.matches(request)) {
  16. chain.addInterceptor(mappedInterceptor.getInterceptor());
  17. }
  18. }
  19. else {
  20. chain.addInterceptor(interceptor);
  21. }
  22. }
  23. return chain;
  24. }
  1. #HandlerExecutionChain
  2. private final Object handler;
  3. private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
  4. private int interceptorIndex = -1;
  5. /**
  6. * Apply preHandle methods of registered interceptors.
  7. * @return {@code true} if the execution chain should proceed with the
  8. * next interceptor or the handler itself. Else, DispatcherServlet assumes
  9. * that this interceptor has already dealt with the response itself.
  10. * 正序处理,并记录执行的拦截器顺序索引
  11. */
  12. boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
  13. for (int i = 0; i < this.interceptorList.size(); i++) {
  14. HandlerInterceptor interceptor = this.interceptorList.get(i);
  15. if (!interceptor.preHandle(request, response, this.handler)) {
  16. triggerAfterCompletion(request, response, null);
  17. return false;
  18. }
  19. this.interceptorIndex = i;
  20. }
  21. return true;
  22. }
  23. /**
  24. * Apply postHandle methods of registered interceptors.
  25. * 成功执行了目标方法以后,才会执行后置拦截器,倒序执行
  26. */
  27. void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
  28. throws Exception {
  29. for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
  30. HandlerInterceptor interceptor = this.interceptorList.get(i);
  31. interceptor.postHandle(request, response, this.handler, mv);
  32. }
  33. }
  34. /**
  35. * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
  36. * Will just invoke afterCompletion for all interceptors whose preHandle invocation
  37. * has successfully completed and returned true.
  38. * 要前置处理成功执行的,索引记录的,才会执行完成处理器,有可能目标方法没有执行,
  39. * 比如目标方法报错,前置报错,后置报错都会触发完成处理器
  40. */
  41. void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
  42. for (int i = this.interceptorIndex; i >= 0; i--) {
  43. HandlerInterceptor interceptor = this.interceptorList.get(i);
  44. try {
  45. interceptor.afterCompletion(request, response, this.handler, ex);
  46. }
  47. catch (Throwable ex2) {
  48. logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
  49. }
  50. }
  51. }

拦截器原理用一张图概括
image.png