一、@WebFilter
Filter 上加 @WebFilter (javax.servlet.annotation.WebFilter),指定 value,启动类加 @ServletComponentScan
【注意】:@ServletComponentScan 这个注解仅对内嵌的 tomcat 生效,如果使用单独的 tomcat,这种方式无效。
示例一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @WebFilter(filterName = "aFilter", value = "/api/amber/*") public class AFilter implements Filter { private static final Logger LOGGER = LoggerFactory.getLogger(AFilter.class); @Autowired private UserService userService; @Override public void init(FilterConfig filterConfig) { LOGGER.info("A Filter初始化,只初始化一次..."); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { LOGGER.info("AFilter 处理中..."); User user = userService.getUserInfo(); LOGGER.info("USER 信息:" + user); HttpServletRequest servletRequest = (HttpServletRequest) request; LOGGER.info(String.valueOf(servletRequest.getRequestURL())); chain.doFilter(request, response); }
@Override public void destroy() { LOGGER.info("A Filter销毁..."); } }
|
示例二:
1 2 3 4 5 6 7 8
| @SpringBootApplication @ServletComponentScan @MapperScan({"com.amber.common.dao"}) public class BronzeApplication { public static void main(String[] args) { SpringApplication.run(BronzeApplication.class, args); } }
|
示例三:
1 2 3 4 5 6 7 8
| 2022-12-01 12:28:38.785 INFO 7052 --- [ main] com.amber.common.filter.AFilter : A Filter初始化,只初始化一次... 2022-12-01 12:28:39.827 INFO 7052 --- [ main] com.amber.common.BronzeApplication : Started BronzeApplication in 2.267 seconds (JVM running for 2.808) 2022-12-01 12:28:44.342 INFO 7052 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2022-12-01 12:28:44.342 INFO 7052 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2022-12-01 12:28:44.345 INFO 7052 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms 2022-12-01 12:28:44.350 INFO 7052 --- [nio-8080-exec-1] com.amber.common.filter.AFilter : AFilter 处理中... 2022-12-01 12:28:44.350 INFO 7052 --- [nio-8080-exec-1] com.amber.common.filter.AFilter : USER 信息:User(screen_name=amber, text=今天星期四, created_at=Thu Dec 01 12:28:44 CST 2022) 2022-12-01 12:28:44.350 INFO 7052 --- [nio-8080-exec-1] com.amber.common.filter.AFilter : http:
|
可以看到输出日志是正确的。
二、@Component + FilterRegistrationBean
在 Filter 上加 @Component ,通过 FilterRegistrationBean addUrlPatterns 进行实例注册。
示例一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Component public class AFilter implements Filter { private static final Logger LOGGER = LoggerFactory.getLogger(AFilter.class); @Autowired private UserService userService; @Override public void init(FilterConfig filterConfig) { LOGGER.info("A Filter初始化,只初始化一次..."); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { LOGGER.info("AFilter 处理中..."); User user = userService.getUserInfo(); LOGGER.info("USER 信息:" + user); HttpServletRequest servletRequest = (HttpServletRequest) request; LOGGER.info(String.valueOf(servletRequest.getRequestURL())); chain.doFilter(request, response); }
@Override public void destroy() { LOGGER.info("A Filter销毁..."); } }
|
示例二:
1 2 3 4 5 6 7 8 9 10 11 12
| @Configuration public class ComponentFilterOrderConfig {
@Bean public FilterRegistrationBean filterBeanOne(AFilter aFilter) { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(aFilter); filterRegistrationBean.addUrlPatterns("/api/amber/*"); filterRegistrationBean.setName("aFilter"); return filterRegistrationBean; } }
|
示例三:
1 2 3 4 5 6 7 8
| 2022-12-01 12:34:48.366 INFO 16188 --- [ main] com.amber.common.filter.AFilter : A Filter初始化,只初始化一次... 2022-12-01 12:34:49.458 INFO 16188 --- [ main] com.amber.common.BronzeApplication : Started BronzeApplication in 2.283 seconds (JVM running for 2.816) 2022-12-01 12:34:54.176 INFO 16188 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2022-12-01 12:34:54.176 INFO 16188 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2022-12-01 12:34:54.180 INFO 16188 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms 2022-12-01 12:34:54.184 INFO 16188 --- [nio-8080-exec-1] com.amber.common.filter.AFilter : AFilter 处理中... 2022-12-01 12:34:54.184 INFO 16188 --- [nio-8080-exec-1] com.amber.common.filter.AFilter : USER 信息:User(screen_name=amber, text=今天星期四, created_at=Thu Dec 01 12:34:54 CST 2022) 2022-12-01 12:34:54.184 INFO 16188 --- [nio-8080-exec-1] com.amber.common.filter.AFilter : http:
|
可以看到输出日志是正确的。
三、前方高能:@WebFilter + @Component 同时使用
切莫 @WebFilter 指定 value 后又加 @Component,会注册两个 filter,导致走两次
示例一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Component @WebFilter(filterName = "aFilter", value = "/api/amber/*") public class AFilter implements Filter { private static final Logger LOGGER = LoggerFactory.getLogger(AFilter.class); @Autowired private UserService userService; @Override public void init(FilterConfig filterConfig) { LOGGER.info("A Filter初始化,只初始化一次..."); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { LOGGER.info("AFilter 处理中..."); User user = userService.getUserInfo(); LOGGER.info("USER 信息:" + user); HttpServletRequest servletRequest = (HttpServletRequest) request; LOGGER.info(String.valueOf(servletRequest.getRequestURL())); chain.doFilter(request, response); }
@Override public void destroy() { LOGGER.info("A Filter销毁..."); } }
|
示例二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 2022-12-01 12:38:27.535 INFO 21136 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 831 ms 2022-12-01 12:38:27.557 DEBUG 21136 --- [ main] o.s.b.w.s.ServletContextInitializerBeans : Mapping filters: aFilter urls=[/api/amber
|
可以看到输出日志已经不是期望的结果,发现:
- AFilter init() 初始化 两次
- AFilter doFilter() 处理中 两次
在 ApplicationFilterChain Debug 中发现注册了两个 Filter 分别是:AFilter 和 aFilter,导致走两次。
@WebFilter + @Component 同时使用需注意
两个方法全部都一起用是没问题的,会覆盖,切忌的是,
只用 @WebFilter + @Component,不用 @ServletComponentScan 和 FilterRegistrationBean,
这时如果 webFilter 配置的是非全局的过滤器,就会被 @Component 注解再注册一个全局的过滤器了。
其中:
当访问的 url 为 /index/*
或者 /product/*
的时候,该过滤器也执行了!也就是说,WebFilter 注解配置的 urlPatterns 没有起作用。【注意】:@WebFilter 中的 value 属性等价于 urlPatterns 属性,但是两个不应该同时使用。
@WebFilter(filterName = "aFilter", value = "/api/amber/*")
中的 value(或者 urlPatterns)属性,
也可以通过 @Component + FilterRegistrationBean 进行实例注册方式:filterRegistrationBean.addUrlPatterns("/*");
解决。
小插曲:
当浏览器访问 http://localhost:8080/index
发现日志输出了两次, doFilter() 方法执行了两次。
示例一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @WebFilter(filterName = "aFilter", value = "/*") public class AFilter implements Filter { private static final Logger LOGGER = LoggerFactory.getLogger(AFilter.class); @Autowired private UserService userService; @Override public void init(FilterConfig filterConfig) { LOGGER.info("A Filter初始化,只初始化一次..."); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { LOGGER.info("AFilter 处理中..."); User user = userService.getUserInfo(); LOGGER.info("USER 信息:" + user); }
@Override public void destroy() { LOGGER.info("A Filter销毁..."); } }
|
示例二:
1 2 3 4 5 6 7 8 9 10 11
| 2022-11-30 23:55:43.928 INFO 22280 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 795 ms 2022-11-30 23:55:43.952 INFO 22280 --- [ main] com.amber.common.filter.AFilter : A Filter初始化,只初始化一次... 2022-11-30 23:55:44.022 INFO 22280 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2022-11-30 23:55:44.170 INFO 22280 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2022-11-30 23:56:03.418 INFO 22280 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2022-11-30 23:56:03.418 INFO 22280 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2022-11-30 23:56:03.423 INFO 22280 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms 2022-11-30 23:56:03.431 INFO 22280 --- [nio-8080-exec-1] com.amber.common.filter.AFilter : AFilter 处理中... 2022-11-30 23:56:03.431 INFO 22280 --- [nio-8080-exec-1] com.amber.common.filter.AFilter : USER 信息:User(screen_name=amber, text=今天星期三, created_at=Wed Nov 30 23:56:03 CST 2022) 2022-11-30 23:56:03.455 INFO 22280 --- [nio-8080-exec-6] com.amber.common.filter.AFilter : AFilter 处理中... 2022-11-30 23:56:03.456 INFO 22280 --- [nio-8080-exec-6] com.amber.common.filter.AFilter : USER 信息:User(screen_name=amber, text=今天星期三, created_at=Wed Nov 30 23:56:03 CST 2022)x
|
打开 Network 发现实际的网络请求有两个:
/index
—— 实际请求
/favicon.ico
——浏览器展示tab上的网站图标。
示例三:
1 2 3 4 5 6 7 8
| @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { LOGGER.info("AFilter 处理中..."); User user = userService.getUserInfo(); LOGGER.info("USER 信息:" + user); HttpServletRequest servletRequest = (HttpServletRequest) request; LOGGER.info(servletRequest.getRequestURI()); }
|
通过 doFilter() 方法中获取 HttpServletRequest 的 getRequestURI() 方法 中发现有 /favicon.ico
请求。
示例四:
1 2 3 4 5 6 7 8 9
| 2022-12-01 00:11:11.428 INFO 13616 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2022-12-01 00:11:11.428 INFO 13616 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2022-12-01 00:11:11.431 INFO 13616 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms 2022-12-01 00:11:11.436 INFO 13616 --- [nio-8080-exec-2] com.amber.common.filter.AFilter : AFilter 处理中... 2022-12-01 00:11:11.436 INFO 13616 --- [nio-8080-exec-2] com.amber.common.filter.AFilter : USER 信息:User(screen_name=amber, text=今天星期三, created_at=Thu Dec 01 00:11:11 CST 2022) 2022-12-01 00:11:11.436 INFO 13616 --- [nio-8080-exec-2] com.amber.common.filter.AFilter : /index 2022-12-01 00:11:11.449 INFO 13616 --- [nio-8080-exec-6] com.amber.common.filter.AFilter : AFilter 处理中... 2022-12-01 00:11:11.449 INFO 13616 --- [nio-8080-exec-6] com.amber.common.filter.AFilter : USER 信息:User(screen_name=amber, text=今天星期三, created_at=Thu Dec 01 00:11:11 CST 2022) 2022-12-01 00:11:11.450 INFO 13616 --- [nio-8080-exec-6] com.amber.common.filter.AFilter : /favicon.ico
|
小插曲是因为浏览器会自动发一个获取网站图标的请求,而过滤器配置的是全局过滤器,所以就会走两次
Title: 为非全局路径配置 Filter 的两种方法
Author: Amber
Date: 2022-12-01
Last Update: 2024-10-29
Blog Link: https://wyiyi.github.io/amber/2022/12/01/filter-note/
Copyright Declaration: Copyright © 2022 Amber.