百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

拦截器(Interceptor)与适配器(HandlerAdapter)

liebian365 2024-10-19 07:56 66 浏览 0 评论

前言:前一节已经介绍完springmvc的请求映射器RequestMappingHandlerMapping,已经完成根据http请求的uri及请求方式(GET,POST)等特征匹配对应controller的method.这一节来介绍下请求适配器RequestMappingHandlerAdpater的获取,该对象是用于后续如何反射调用,以及开发中常见的拦截器原理.

1.概述

我们还是接着看DispatcherServlet的doDispatch方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    try {
        // 省略...
        try {
            // 省略...
            // 上节的HandlerExecutionChain,包含两类东西
            // 1.方法控制器(HandlerMethod)
            // 2.拦截器,包含我们自定义的拦截器及
            // RequestMappingHandlerMapping默认拦截器
            // (ConversionServiceExposingInterceptor,ResourceUrlProviderExposingInterceptor)
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // A.根据HandlerMethod获取适配器RequestMappingHandlerAdapter
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            // 省略 last-modified...
            String method = request.getMethod();

            // B.调用拦截器的前置处理
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            // 通过适配器完成controller对应method的调用(下节分享)
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            // 省略视图解析...
            // C.调用拦截器的后置处理
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        // 全局异常处理器(下下节分享)
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        // D.拦截器执行完毕回调
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        // D.拦截器执行完毕回调
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                               new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                //异步请求才会走拦截器的该方法,这里与tomcat的处理机制有关,不做过多解读
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        // 省略...
    }
}

2.拦截器加载

为了与当前流行的web框架结合,从这节看是我们从springboot的视角来分析DispatcherServlet,与springmvc中不同之处是,springboot使用了自动装载机制。基本流程如下:

  • 在META-INF文件夹下创建spring.factories文件,并在文件中定义key,value形式的键值对(类似于propreties文件)
  • 加载文件中定义bean并注册到spring容器中

2.1.DispatcherServlet加载

首先我们先找到springboot自动配置文件

这里有两个我们需要关注的键值对

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
# 完成DispatcherServlet初始化
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
# 完成自定义web行为配置初始化(自定义拦截器、自定义跨域配置)

我们先看看是如何完成DispatcherServlet初始化的

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
// 声明这是一个配置类,需要将该类中@Bean的方法注入到容器中
@Configuration(proxyBeanMethods = false) 
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {

	public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";

	@Configuration(proxyBeanMethods = false)	// 同上
	@Conditional(DefaultDispatcherServletCondition.class)
	@ConditionalOnClass(ServletRegistration.class)
	@EnableConfigurationProperties(WebMvcProperties.class)
	protected static class DispatcherServletConfiguration {

      @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
      public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
               // 这里完成DispatcherServlet的初始化
        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
        dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
        dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
        dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
        dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
        return dispatcherServlet;
      }
    }
}

当请求第一次DispatcherServlet第一次请求Http请求时会初始化RequestMappingHandlerMapping与RequestMappingHandlerAdapter。

protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}
// 下面就是DispatcherServlet的初始化了,可以看前一篇的文章

2.2.RequestMappingHandlerMapping加载

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
    
    // 该注解不只会将其方法中的bean注入到spring容器中,还会为当前的类创建bean并注入到spring容器中.
    @Configuration(proxyBeanMethods = false) 
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
        @Bean
        @Primary
        @Override
        public RequestMappingHandlerMapping requestMappingHandlerMapping(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
            // Must be @Primary for MvcUriComponentsBuilder to work
            // 这里进行RequestMappingHandlerMapping加载,并注入spring容器
            return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
                                                      resourceUrlProvider);
        }
    }
}

我们先看看EnableWebMvcConfiguration类结构关系图

由上图可知requestMappingHandlerMapping执行的是父类WebMvcConfigurationSupport的requestMappingHandlerMapping方法,我们一起来看一下.

// WebMvcConfigurationSupport
public RequestMappingHandlerMapping requestMappingHandlerMapping(
    @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
    @Qualifier("mvcConversionService") FormattingConversionService conversionService,
    @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

    // 1.new RequestMappingHandlerMapping
    RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
    // 2.设置排序,当DispatcherServlet获取HandlerMapping实现类时,该对象位于第一个,
    // 也就是为RequestMappingHandlerMapping是DispatcherServlet默认的Mapping处理器的原因
    mapping.setOrder(0);
    // 3.设置拦截器
    mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
    mapping.setContentNegotiationManager(contentNegotiationManager);
    // 4.跨域设置
    mapping.setCorsConfigurations(getCorsConfigurations());
    // 省略...
    return mapping;
}

2.3.EnableWebMvcConfiguration加载

当EnableWebMvcConfiguration初始化时会做两件事情:

  • 将其父类DelegatingWebMvcConfigurationWebMvcConfigurationSupport初始化。
  • 将初始化的实例(包含父类)进行依赖注入:1、带有@Autowired成员变量注入,2、带有@Autowired的方法注入变量并执行。
@Configuration(proxyBeanMethods = false)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {

    public EnableWebMvcConfiguration(ResourceProperties resourceProperties,
                                     ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
                                     ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, 
                                     ListableBeanFactory beanFactory) {
        this.resourceProperties = resourceProperties;
        this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
        this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
        this.beanFactory = beanFactory;
    }
}

// 父类
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

	// EnableWebMvcConfiguration依赖注入
    // 这里会从容器中寻找类型为WebMvcConfigurer.class的对象,作为configurers的参数,然后执行当前方法
    // 将WebMvcConfigurer存储在WebMvcConfigurerComposite中
    @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }
}

// 引用
class WebMvcConfigurerComposite implements WebMvcConfigurer {

    // 自定义webmvc配置器会存放到这里,这里面也包含自定义拦截器(MyInterceptor)
    private final List<WebMvcConfigurer> delegates = new ArrayList<>();


    public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.delegates.addAll(configurers);
        }
    }
}

我们是如何自定义WebMvcConfigurer对象的呢?

@Component
public class WebConfiguration implements WebMvcConfigurer {

    // 拦截请求
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }

    // 跨域支持
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowCredentials(true).allowedHeaders("*").allowedOrigins("*")
            .allowedMethods("HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE");
    }
}

public class MyInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
                             Object handler) throws Exception {
        // 如果这里返回false,整个DispatcherServlet的调用就到此结束了
        System.out.println("pre........");
        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, 
                           Object handler, ModelAndView modelAndView) throws Exception {
        // 只有pre返回true的时候才会走这里,pre碰到异常也不会走这里
        System.out.println("post.........");
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
                                Object handler, Exception ex) throws Exception {
        // 不论pre返回true还是false,还是碰到任何异常,都会走这里
        System.out.println("afterCompletion...");
        super.afterCompletion(request, response, handler, ex);
    }

    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, 
                                               Object handler) throws Exception {
        System.out.println("afterConcurrentHandlingStarted...");
        super.afterConcurrentHandlingStarted(request, response, handler);
    }
}

上面完成了2个工作:

  • 完成了自定义webmvc配置器(WebConfiguration)初始化,并完成自定义拦截器MyInterceptor挂载,且将该对象注入到容器中。
  • 完成DelegatingWebMvcConfiguration依赖注入(setConfigurers),并完成自定义webmvc配置WebConfiguration的挂载,此时自定义拦截器MyInterceptor已经挂载到DelegatingWebMvcConfiguration中。

2.4.拦截器加载

拦截器也是通过springboot自动装配类(WebMvcConfigurationSupport)加载进spring容器的

2.4.1.拦截器加载

// WebMvcConfigurationSupport
public RequestMappingHandlerMapping requestMappingHandlerMapping(
    @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
    @Qualifier("mvcConversionService") FormattingConversionService conversionService,
    @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
	// ...
    // 3.设置拦截器
    mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
	// ...
    return mapping;
}

// WebMvcConfigurationSupport
protected final Object[] getInterceptors(
    FormattingConversionService mvcConversionService,
    ResourceUrlProvider mvcResourceUrlProvider) {
    if (this.interceptors == null) {
        // 创建默认的InterceptorRegistry
        InterceptorRegistry registry = new InterceptorRegistry();
        addInterceptors(registry);
        registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
        registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
        // 原始拦截器的包装在这里
        this.interceptors = registry.getInterceptors();
    }
    return this.interceptors.toArray();
}

public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
	// 2.3.EnableWebMvcConfiguration初始化时已经将自定义的WebConfiguration加载进来了,其中包含MyInterceptor
	private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
    
    protected void addInterceptors(InterceptorRegistry registry) {
        // 这里将自定义的WebConfiguration交给了InterceptorRegistry
        this.configurers.addInterceptors(registry);
    }
}

class WebMvcConfigurerComposite implements WebMvcConfigurer {

	private final List<WebMvcConfigurer> delegates = new ArrayList<>();
    
    public void addInterceptors(InterceptorRegistry registry) {
        // 遍历之前加载进来的自定义WebConfiguration
        for (WebMvcConfigurer delegate : this.delegates) {
            // 这里回调自定义的WebConfiguration的addInterceptors方法
		   // 看自定义addInterceptors方法逻辑
            delegate.addInterceptors(registry);
        }
    }
}

// 自定义WebConfiguration
public class WebConfiguration implements WebMvcConfigurer {
    
    // 把自定义的拦截器添加拦截器chain,并定义拦截规则
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}

// 原始拦截器的包装
protected List<Object> getInterceptors() {
    return this.registrations.stream()
        .sorted(INTERCEPTOR_ORDER_COMPARATOR)
        .map(InterceptorRegistration::getInterceptor)
        .collect(Collectors.toList());
}

// 看看InterceptorRegistration::getInterceptor方法
protected Object getInterceptor() {
    // 如果拦截与不拦截的正则过滤器均为空,那么这里直接返回
    if (this.includePatterns.isEmpty() && this.excludePatterns.isEmpty()) {
        return this.interceptor;
    }

    String[] include = StringUtils.toStringArray(this.includePatterns);
    String[] exclude = StringUtils.toStringArray(this.excludePatterns);
    // 如果不为空,这里需要将我们的拦截器包装到MappedInterceptor对象中
    // 我们自定义的拦截器MyInterceptor添加了匹配路径正则,所以会被包装成MappedInterceptor
    // 这个在我们在获取拦截的的时候会用到
    MappedInterceptor mappedInterceptor = new MappedInterceptor(include, exclude, this.interceptor);
    if (this.pathMatcher != null) {
        mappedInterceptor.setPathMatcher(this.pathMatcher);
    }
    return mappedInterceptor;
}

至此自定义拦截器被加载到RequestMappingHandlerMapping对象中.

2.4.2.拦截器包装

当我们加载到RequestMappingHandlerMapping中的拦截器有可能属于WebRequestInterceptor类型,需要将该类型的拦截器转换成HandlerInterceptor类型,所以对拦截器做了如下转换,这个转换也是在spring bean初始化的时候处理,请看下图

AbstractAutowireCapableBeanFactory是所有spring bean初始化都要走的流程,明显该动作是在RequestMappingHandlerMapping执行自定义init方法之前执行的回调,具体执行回调的后置处理器为ApplicationContextAwareProcessor.我们看代码

// ApplicationContextAwareProcessor
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    // ...
    invokeAwareInterfaces(bean);
    return bean;
}

private void invokeAwareInterfaces(Object bean) {
    // ....
    if (bean instanceof ApplicationContextAware) {
        ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    }
}

// ApplicationObjectSupport
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
    if (context == null && !isContextRequired()) {
        // Reset internal context state.
        this.applicationContext = null;
        this.messageSourceAccessor = null;
    }
    else if (this.applicationContext == null) {
        // ...
        initApplicationContext(context);
    }
    else {
        // ...
    }
}

// 拦截器规范化
// AbstractHandlerMapping
protected void initInterceptors() {
    if (!this.interceptors.isEmpty()) {
        for (int i = 0; i < this.interceptors.size(); i++) {
            Object interceptor = this.interceptors.get(i);
            if (interceptor == null) {
                throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
            }
            this.adaptedInterceptors.add(adaptInterceptor(interceptor));
        }
    }
}

// AbstractHandlerMapping
// 这里将EnableWebMvcConfiguration加载的拦截器转换到了adaptedInterceptors成员变量中
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
    if (interceptor instanceof HandlerInterceptor) {
        return (HandlerInterceptor) interceptor;
    }
    else if (interceptor instanceof WebRequestInterceptor) {
        return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
    }
    else {
        throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
    }
}

2.5.拦截器获取

接着回到DispatcherServlet的解析请求的核心方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    try {
        // 省略...
        try {
            // ...
            // 
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // A.根据HandlerMethod获取适配器RequestMappingHandlerAdapter
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            // 省略 last-modified...
            String method = request.getMethod();

            // B.调用拦截器的前置处理
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            // 通过适配器完成controller对应method的调用(下节分享)
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            // 省略视图解析...
            // C.调用拦截器的后置处理
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // ...
        }
        // 全局异常处理器(下下节分享)
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        // D.拦截器执行完毕回调
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        // D.拦截器执行完毕回调
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                               new NestedServletException("Handler processing failed", err));
    }
}

2.5.1拦截器获取

// DispatcherServlet
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;
}

// AbstractHandlerMapping(RequestMappingHandlerMapping)
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 1.获取HandlerMethod,就是找到哪个Controller的Method,用于方法的反射调用.这里包含method及待调用的bean
    Object handler = getHandlerInternal(request);

    // 2.获取Handler调用链,包含了所有的拦截器
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
	// ...

    return executionChain;
}

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                     (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    // 还记得这个对象(adaptedInterceptors)吗,这个就是2.4.2.节拦截器规范会之后的存储对象
    // 其中包含我们自定义的拦截器
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            // 还记得2.4.1.包装拦截器时,如果有设置匹配路径时会被封装成MappedInterceptor,这里就用到了
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            // 这里是匹配http请求的url,如果能匹配上才把该过滤器添加到此次请求的拦截器中
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

2.6.拦截器执行

再来看DisptcherServlet的doDisptach方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    try {
        // 省略...
        try {
            //...
            // B.调用拦截器的前置处理
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            // 完成controller对应method的调用(下节分享)
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            // C.调用拦截器的后置处理
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // ...
        }
        // 全局异常处理器(下下节分享),该方法中也包含triggerAfterCompletion方法,即D.拦截器执行完毕回调
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        // D.拦截器执行完毕回调
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        // D.拦截器执行完毕回调
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                               new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                // E.并发执行完成回调
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            // Clean up any resources used by a multipart request.
            // 这里是清除文件上传的内存缓存,我们一般通过multipart/form-data头处理文件上传
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

2.6.1.前置回调

前置处理就是上面(2.6)B的位置

// 	HandlerExecutionChain
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 获取拦截器(包含自定义的MyInterceptor)
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = 0; i < interceptors.length; i++) {
            HandlerInterceptor interceptor = interceptors[i];
            // 调用前置处理方法,这里的interceptor也有子集定义的拦截器MyInterceptor
            // 这里就是执行自定义拦截器的前置处理方法
            // 这里的handler就是从RequestMappingHandlerMapping获取到的
            // HandlerMethod(包含待调用的controller的方法及controller对象)
            if (!interceptor.preHandle(request, response, this.handler)) {
                triggerAfterCompletion(request, response, null);
                return false;
            }
            this.interceptorIndex = i;
        }
    }
    return true;
}

2.6.2.后置回调

后置处理就是上面(2.6)C的位置

// 	HandlerExecutionChain
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
    throws Exception {
	
    // 获取拦截器(包含MyInterceptor)
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = interceptors.length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            // 执行拦截器后置操作(包含MyInterceptor)
            interceptor.postHandle(request, response, this.handler, mv);
        }
    }
}

2.6.3.执行完成回调

后置处理就是上面(2.6)D的位置

// 	HandlerExecutionChain
private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response,
                                    @Nullable HandlerExecutionChain mappedHandler, Exception ex) throws Exception {

    if (mappedHandler != null) {
        // 完成自定义回调
        mappedHandler.triggerAfterCompletion(request, response, ex);
    }
    throw ex;
}

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
    throws Exception {

    // 获取拦截器(包含MyInterceptor)
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = this.interceptorIndex; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            try {
                // 执行拦截器controller方法执行完毕回调操作(包含MyInterceptor)
                interceptor.afterCompletion(request, response, this.handler, ex);
            }
            catch (Throwable ex2) {
                logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
            }
        }
    }
}

2.6.4.并发执行已开始回调

并发执行已开始回调就是上面(2.6)E的位置

// 	HandlerExecutionChain
void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
    // 获取拦截器(包含MyInterceptor)
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = interceptors.length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            if (interceptor instanceof AsyncHandlerInterceptor) {
                try {
                    AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptor;
                    // 执行并发完成回调
                    asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
                }
                //...
            }
        }
    }
}

3.适配器加载(预告)

适配器的加载与路径映射器(RequestMappingHandlerMapping)的加载基本一致,也是通过EnableWebMvcConfiguration加载进来的,接着看代码吧

// EnableWebMvcConfiguration
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
    @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
    @Qualifier("mvcConversionService") FormattingConversionService conversionService,
    @Qualifier("mvcValidator") Validator validator) {
    RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,
                                                                              conversionService, validator);
    adapter.setIgnoreDefaultModelOnRedirect(
        this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
    return adapter;
}

// WebMvcConfigurationSupport
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
    @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
    @Qualifier("mvcConversionService") FormattingConversionService conversionService,
    @Qualifier("mvcValidator") Validator validator) {

    // 1.这里就是new RequestMappingHandlerAdapter()
    RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
    // 省略各种配置加载...
    // 下期分享方法调用时再来分详细拆解

    return adapter;
}

spring加载的逻辑同RequestMappingHandlerMapping一致,下期也会像RequestMappingHandlerMapping一样画一幅RequestMappingHandlerAdapter一样的加载流程图.再回到DispatcherServlet处理每次请求的主流程doService->doDispatch方法

// DisptcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 我们看看每次请求是如何获取HandlerAdapter的
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
}

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    // 这里的handler就是从上一步getHandler中带来的HandlerMethod
    if (this.handlerAdapters != null) {
        // 这里的handlerAdapters也是通过onRefresh方法加载到DispatcherServlet对象中
        for (HandlerAdapter adapter : this.handlerAdapters) {
            // 这里主要看RequestMappingHandlerAdapter的supports方法
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
}

// AbstractHandlerMethodAdapter(RequestMappingHandlerAdapter)
@Override
public final boolean supports(Object handler) {
    // 1.这里handler就是从上期RequestMappingHandlerMapping中获取的HandlerMethod(包含controller待执行的method)
    // 2.supportsInternal方法默认返回true
    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
    return true;
}

到此我们知道返回的HandlerAdapter为RequestMappingHandlerAdapter.

4.思考

  • 拦截器一共有4种回调方式,当我们前置回调碰到异常时,后置回调执行完成回调还会正常进行吗?这种逻辑与我们定义aop切面到全部的controller上有什么区别呢?

相关推荐

“版本末期”了?下周平衡补丁!国服最强5套牌!上分首选

明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...

VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符&quot;

首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...

东营交警实名曝光一批酒驾人员名单 88人受处罚

齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...

Qt界面——搭配QCustomPlot(qt platform)

这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...

大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写

老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...

测试谷歌VS Code AI 编程插件 Gemini Code Assist

用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...

顾爷想知道第4.5期 国服便利性到底需优化啥?

前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...

掌握Visual Studio项目配置【基础篇】

1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...

还嫌LED驱动设计套路深?那就来看看这篇文章吧

随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...

Visual Studio Community 2022(VS2022)安装图文方法

直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...

Qt添加MSVC构建套件的方法(qt添加c++11)

前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...

Qt为什么站稳c++GUI的top1(qt c)

为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...

qt开发IDE应该选择VS还是qt creator

如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...

Qt 5.14.2超详细安装教程,不会来打我

Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...

Cygwin配置与使用(四)——VI字体和颜色的配置

简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...

取消回复欢迎 发表评论: