1.过滤器作用在什么地方
对web发送的请求拦截进行环绕处理
2.如何编写代码
方式一
实现Filter接口,加上注解@WebFilter,根据其中的urlPatterns过滤请求。主类加上注解@ServletComponentScan,basePackages值为filter所在的包
@WebFilter(filterName = "myFilter",urlPatterns = "/path")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//filter初始化的时候调用
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//请求会先到这里,然后在到controller层
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
//filter被销毁的收调用
Filter.super.destroy();
}
}
在主方法类上加上注解,包路径为filter类所在的包
@ServletComponentScan(basePackages = {})
方式二
实现Filter接口。按照以下方式加配置类。
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Configuration
public class Configuration {
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MyFilter());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.setUrlPatterns(Collections.singleton("/user"));
filterRegistrationBean.setName("myFilter");
return filterRegistrationBean;
}
}
3.产生的问题
3.1 过滤路径不起作用
什么时候判断拦截路径?
ApplicationFilterFactory#createFilterChain()
将所有的filter取出来,筛选和requestPath符合的Filter放到filterChain中
//取所有的filter
FilterMap[] filterMaps = context.findFilterMaps();
if (filterMaps != null && filterMaps.length != 0) {
DispatcherType dispatcher = (DispatcherType)request.getAttribute("org.apache.catalina.core.DISPATCHER_TYPE");
String requestPath = null;
Object attribute = request.getAttribute("org.apache.catalina.core.DISPATCHER_REQUEST_PATH");
if (attribute != null) {
requestPath = attribute.toString();
}
String servletName = wrapper.getName();
FilterMap[] var10 = filterMaps;
int var11 = filterMaps.length;
int var12;
FilterMap filterMap;
ApplicationFilterConfig filterConfig;
for(var12 = 0; var12 < var11; ++var12) {
filterMap = var10[var12];
if (matchDispatcher(filterMap, dispatcher) && matchFiltersURL(filterMap, requestPath)) {
filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMap.getFilterName());
if (filterConfig != null) {
filterChain.addFilter(filterConfig);
}
}
}
}
ApplicationFilterFactory#matchFiltersURL()
根据Filter中的urlPattern对请求路径进行筛选,符合条件的放到filterChain 中
private static boolean matchFiltersURL(FilterMap filterMap, String requestPath) {
if (filterMap.getMatchAllUrlPatterns()) {
return true;
} else if (requestPath == null) {
return false;
} else {
String[] testPaths = filterMap.getURLPatterns();
String[] var3 = testPaths;
int var4 = testPaths.length;
for(int var5 = 0; var5 < var4; ++var5) {
String testPath = var3[var5];
if (matchFiltersURL(testPath, requestPath)) {
return true;
}
}
return false;
}
}
执行的时候,按照filterChain中的filter执行
@Component+@WebFilter 配置过滤路径也不起作用
通过@Component将实现类放入到容器中,不添加注解@ServletComponentScan
@Component
@WebFilter(filterName = "myFilter",urlPatterns = "/path")
public class MyFilter implements Filter{}
为什么使用@ServletComponentScan生效 @Component不生效
//WebFilterHandler#doHandle() 解析了@WebFilter注解
public void doHandle(Map<String, Object> attributes, AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterRegistrationBean.class);
builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
builder.addPropertyValue("dispatcherTypes", this.extractDispatcherTypes(attributes));
builder.addPropertyValue("filter", beanDefinition);
builder.addPropertyValue("initParameters", this.extractInitParameters(attributes));
String name = this.determineName(attributes, beanDefinition);
builder.addPropertyValue("name", name);
builder.addPropertyValue("servletNames", attributes.get("servletNames"));
//将urlPatterns放入FilterRegistrationBean中
builder.addPropertyValue("urlPatterns", this.extractUrlPatterns(attributes));
registry.registerBeanDefinition(name, builder.getBeanDefinition());
}
//记录了拦截路径
@Component未进行对@WebFilter注解的解析
添加到FilterMap中的Filter
AbstractFilterRegistrationBean#configure() 如果urlPatterns为空添加的则为“/*”
private static final String[] *DEFAULT_URL_MAPPINGS* = new String[]{"/*"};
if (servletNames.isEmpty() && this.urlPatterns.isEmpty()) {
registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,DEFAULT_URL_MAPPINGS);
} else {
if (!servletNames.isEmpty()) {
registration.addMappingForServletNames(dispatcherTypes, this.matchAfter, StringUtils.toStringArray(servletNames));
}
if (!this.urlPatterns.isEmpty()) {
registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter, StringUtils.toStringArray(this.urlPatterns));
}
}
所以通过@Component注入,即使在@WebFilter中配置了url也会拦截所有的请求。
相同的过滤器代码
@WebFilter(urlPatterns = "/user")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("myFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
}
@ServletComponentScan
@Component
3.2 过滤器执行顺序问题
ApplicationFilterChain#doFilter()
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
//省略部分代码
//执行filter方法
this.internalDoFilter(request, response);
}
ApplicationFilterChain#internalDoFilter()
private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if (this.pos < this.n) {
//根据获取到的filter顺序执行
ApplicationFilterConfig filterConfig = this.filters[this.pos++];
try {
Filter filter = filterConfig.getFilter();
if (request.isAsyncSupported() && "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
}
if (Globals.IS_SECURITY_ENABLED) {
Principal principal = ((HttpServletRequest)request).getUserPrincipal();
Object[] args = new Object[]{request, response, this};
SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
} else {
filter.doFilter(request, response, this);
}
} catch (ServletException | RuntimeException | IOException var15) {
throw var15;
} catch (Throwable var16) {
Throwable e = ExceptionUtils.unwrapInvocationTargetException(var16);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
}
//省略部分代码
}
@Order和@Component 可以保证filter的执行顺序
@Order(1)
@Component
@WebFilter(urlPatterns = "/user")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("myFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Order(-1)
@Component
@WebFilter(urlPatterns = "/user")
public class MyFilter2 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("myFilter2");
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Order和@ServletComponentScan 不可以保证顺序
@Order(1)
//@Component
@WebFilter(urlPatterns = "/user")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("myFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Order(-1)
//@Component
@WebFilter(urlPatterns = "/user")
public class MyFilter2 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("myFilter2");
filterChain.doFilter(servletRequest, servletResponse);
}
}
@ServletComponentScan("com.test.filter")
public class Application
按照name排序,@Order注解未起作用
通过@Configuration配置的filter会按照配置的order顺序执行
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MyFilter());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.setUrlPatterns(Collections.singleton("/user"));
filterRegistrationBean.setName("myFilter");
return filterRegistrationBean;
}
@Bean
public FilterRegistrationBean myFilter2(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MyFilter2());
filterRegistrationBean.setOrder(-1);
//filterRegistrationBean.setUrlPatterns(Collections.singleton("/user"));
filterRegistrationBean.setName("myFilter2");
return filterRegistrationBean;
}
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("myFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
}
public class MyFilter2 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("myFilter2");
filterChain.doFilter(servletRequest, servletResponse);
}
}