title: SpringMVC —— @WebFilter 注解与 SpringMVC
date: 2020/11/19 17:09
引言
之前同事在写 Filter 的时候发现在 Filter 中无法使用 @Value 等注解进行 DI,代码如下:
@WebFilter("/demo03/*")
public class Filter1 implements Filter {
@Value("${test03.aaa}")
private String aaa;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(aaa);
System.out.println(servletRequest.getParameter("name"));
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
@WebFilter 注解是 servlet3.0 提供的注解,只是为了代替在 web.xml 文件中配置 filter,下面介绍 3 种可以 DI 的配置方法。
配置 Filter
1)@ServletComponentScan 方式(只适用于 jar 包启动方式)
@WebFilter("/demo03/*")
public class Filter1 implements Filter {
...
}
@ServletComponentScan
@SpringBootApplication
public class SpringTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringTestApplication.class, args);
}
}
2)直接加 @Component 注解(错误,不要使用)
@Component
@WebFilter("/demo03/*")
public class Filter1 implements Filter {
...
}
问题:war 包启动时一次请求调用了两次 Filter,一次有 DI 的值一次没有。
image经过测试发现,好像是 Spring 加了一个拦截/*
的过滤器,Tomcat 加了一个拦截/demo03/*
的过滤器(Tomcat 加的没有进行 DI;而且在使用 jar 包启动的时候 Tomcat 不会加拦截器,所以没问题)。
3)通过 FilterRegistrationBean 向容器中注册(一切正常)
@Component
public class Filter1 implements Filter {
...
}
@SpringBootApplication
public class SpringTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringTestApplication.class, args);
}
@Bean
public FilterRegistrationBean<Filter1> func(Filter1 filter1) {
FilterRegistrationBean<Filter1> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(filter1);
registrationBean.addUrlPatterns("/demo03/*");
return registrationBean;
}
}
从上面三种方式可以得出:
- 外部 Tomcat 启动时 Tomcat 会扫描携带 @WebFilter 注解的 Filter 然后加入过滤器链。
- 如果 Filter 上标注了 @Component 注解,则 Spring 会自动将进行 DI 并加入过滤器链中,只不过拦截的地址是
/*
- 第三种配置方式因为没有携带 @WebFilter 注解,所以不会被 Tomcat 扫描,但为啥 Spring 没有为其加两个拦截地址呢? 理论上 @Component -> /* @Bean ->/demo03/* -> 看最后一张图中的 seen 字段
代码解析
@ServletComponentScan
image image image image image发没发现这种方式和我们的第三种配置方式实际上是一样的。
当 Tomcat 启动完成的时候会调用 ServletContainerInitializer 的 onStartup() 方法
image image
网友评论