拦截器(Interceptor)与适配器(HandlerAdapter)
liebian365 2024-10-19 07:56 52 浏览 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初始化时会做两件事情:
- 将其父类DelegatingWebMvcConfiguration、WebMvcConfigurationSupport初始化。
- 将初始化的实例(包含父类)进行依赖注入: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上有什么区别呢?
相关推荐
- 4万多吨豪华游轮遇险 竟是因为这个原因……
-
(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...
- “菜鸟黑客”必用兵器之“渗透测试篇二”
-
"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...
- 科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白
-
作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...
- 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势
-
作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...
- 知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势
-
智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...
- 每日新闻播报(September 14)_每日新闻播报英文
-
AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...
- 香港新巴城巴开放实时到站数据 供科技界研发使用
-
中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...
- 5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper
-
本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...
- Qt动画效果展示_qt显示图片
-
今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...
- 如何从0到1设计实现一门自己的脚本语言
-
作者:dong...
- 三年级语文上册 仿写句子 需要的直接下载打印吧
-
描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...
- C++|那些一看就很简洁、优雅、经典的小代码段
-
目录0等概率随机洗牌:1大小写转换2字符串复制...
- 二年级上册语文必考句子仿写,家长打印,孩子照着练
-
二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)