记录: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 filterRegistrationBean() {
FilterRegistrationBean filterReg = new FilterRegistrationBean();
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日