Spring Web的Filter、DispatcherServlet、HandlerInterceptor、Controller应用和执行顺序以及执行线程

记录:394

场景:在Spring Web项目中,使用Filter、DispatcherServlet、HandlerInterceptor、Controller。验证执行顺序。验证执行线程是同一个。

版本:JDK 1.8,SpringBoot 2.6.3,springCloud 2021.0.1

1.结论

1.1执行顺序

在Spring Web项目中,发起一个http请求,执行顺序依次是:Filter、DispatcherServlet、HandlerInterceptor、Controller。

1.2执行线程

在Spring Web项目中,发起一个http请求,请求执行的Filter、DispatcherServlet、HandlerInterceptor、Controller,使用同一个线程。

2.应用Filter

javax.servlet.Filter,一般翻译为过滤器,是一个接口。

2.1使用自定义Filter步骤

(1)实现Filter接口。

(2)把自定义Filter接口,注册到FilterRegistrationBean中。

2.2实现自定义Filter

@Slf4j
public class HubBaseFilter implements Filter {
  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
    Filter.super.init(filterConfig);
  }
  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    VerifyUtil.printVerifyInfo("Filter->doFilter");
    filterChain.doFilter(servletRequest, servletResponse);
  }
  @Override
  public void destroy() {
    Filter.super.destroy();
  }
}

2.3注册自定义Filter

@Configuration
public class HubBaseFilterConfig {
  //过滤器
  @Bean("baseFilter")
  public HubBaseFilter baseFilter() {
      return new HubBaseFilter();
  }
  //注册过滤器
  @Bean
  public FilterRegistrationBean<HubBaseFilter> filterRegistrationBean() {
    FilterRegistrationBean<HubBaseFilter> filterReg = new FilterRegistrationBean<HubBaseFilter>();
    filterReg.setFilter(baseFilter());
    filterReg.addUrlPatterns("/*");
    filterReg.setOrder(1);
    return filterReg;
  }
}

3.应用DispatcherServlet

org.springframework.web.servlet.DispatcherServlet,是Spring Web实现的Servlet,无需额外实现,直接使用

3.1加载DispatcherServlet逻辑

(1)启动类注解@SpringBootApplication,加载Spring Boot相关配置。

(2)加载@SpringBootApplication注解后,会加载@EnableAutoConfiguration实现Spring Boot自动注解记载功能。

(3)注解@EnableAutoConfiguration加载AutoConfigurationImportSelector类。

(4)加载spring-boot-autoconfigure-2.6.3.jar的/META-INF/spring.factories。

(5)在spring.factories加载,DispatcherServletAutoConfiguration类,全称:org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration。

(6)在DispatcherServletAutoConfiguration中加载DispatcherServlet,全称:org.springframework.web.servlet.DispatcherServlet。

(7)Spring Boot项目正常启动,引入了Spring Web相关的包,就会加载DispatcherServlet。

4.应用HandlerInterceptor

org.springframework.web.servlet.HandlerInterceptor,一般翻译为拦截器,是一个接口。

4.1使用自定义HandlerInterceptor步骤

(1)实现HandlerInterceptor接口。

(2)把自定义HandlerInterceptor接口,注册到InterceptorRegistry中。

4.2实现自定义HandlerInterceptor

@Slf4j
@Component
public class HubBaseHandlerInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  VerifyUtil.printVerifyInfo("HandlerInterceptor->doFilter");
  return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
  VerifyUtil.printVerifyInfo("HandlerInterceptor->postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
  VerifyUtil.printVerifyInfo("HandlerInterceptor->afterCompletion");
}
}

4.3注册自定义HandlerInterceptor

注册时,实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer接口。

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
  @Autowired
  private HubBaseHandlerInterceptor handlerInterceptor;
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(handlerInterceptor).addPathPatterns("/**");
  }
}

5.应用Controller

5.1使用自定义Controller步骤

(1)实现自定义CityController类,在其方法中写具体业务。

(2)使用注解@RestController,标记CityController类是一个Controller类。

(3)使用注解@RequestMapping("/hub/example/city"),标记类上请求URL路径。此注解作用在类上。

(4)使用注解@PostMapping("/queryCityByCityName"),标记方法请求URL路径。此注解作用在方法上。

(5)在方法中实现具体业务,而此方法就是对外暴露的Restful接口。

5.2实现Controller

@RestController
@RequestMapping("/hub/example/city")
@Slf4j
public class CityController {
  @PostMapping("/queryCityByCityName")
  public Object queryCityByCityName(String cityName) {
    VerifyUtil.printVerifyInfo("CityController->queryCityByCityName");
    return "执行成功";
  }
}

6.辅助验证类VerifyUtil

6.1VerifyUtil解析

(1)线程休眠1秒,为了增加可识别度。

(2)获取当前执行线程名称。

(3)获取当前时间,精确到时分秒。

(4)打印:执行的类+方法,执行时间,执行线程。

以上,4个步骤可以分辨出过滤器、拦截器、Controller执行顺序。判断Servlet顺序,则只需要在DispatcherServlet的doService中打断点。

6.2VerifyUtil代码

public class VerifyUtil {
  public static void printVerifyInfo(String classAndMethod) {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    String ThreadName = Thread.currentThread().getName();
    String nowTime = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
    System.out.println(classAndMethod + ",执行时间: " + nowTime + ",执行线程: " + ThreadName);
  }
}

7.使用Postman测试

7.1发起http请求

请求URL: http://127.0.0.1:18200/hub-200-base/hub/example/city/queryCityByCityName

入参:cityName=hangzhou

7.2运行打印日志

Filter->doFilter,执行时间: 2023-03-27 19:23:58,执行线程: http-nio-18200-exec-1
HandlerInterceptor->doFilter,执行时间: 2023-03-27 19:23:59,执行线程: http-nio-18200-exec-1
CityController->queryCityByCityName,执行时间: 2023-03-27 19:24:00,执行线程: http-nio-18200-exec-1
HandlerInterceptor->postHandle,执行时间: 2023-03-27 19:24:01,执行线程: http-nio-18200-exec-1
HandlerInterceptor->afterCompletion,执行时间: 2023-03-27 19:24:02,执行线程: http-nio-18200-exec-1

以上,感谢。

2023年3月27日

猜你喜欢

转载自blog.csdn.net/zhangbeizhen18/article/details/129804589