Java过滤器详情指南

目录

  1. 简介
  2. 源码分析
  3. 设计模式
  4. 项目应用场景
  5. 面试高频点
  6. 最佳实践
  7. 总结

简介

什么是Java过滤器

Java过滤器(Filter)是Java Web应用中的一个重要组件,它可以在请求到达Servlet之前和响应返回客户端之前对请求和响应进行预处理和后处理。

核心特性

特性 说明
请求拦截 在请求到达Servlet之前进行拦截和处理
响应处理 在响应返回客户端之前进行处理
链式调用 多个过滤器可以组成过滤器链,按顺序执行
生命周期管理 由容器管理,随Web应用启动而创建,随应用关闭而销毁
配置灵活 支持注解配置和web.xml配置两种方式

过滤器与拦截器的区别

对比项 Filter Interceptor
实现方式 基于函数回调 基于反射机制
使用范围 只能用于Web应用 可以用于Web应用、Spring应用等
获取资源 只能获取ServletContext 可以获取Spring容器中的资源
执行顺序 在Interceptor之前执行 在Filter之后执行
异常处理 不能使用Spring的异常处理机制 可以使用Spring的异常处理机制

源码分析

1. Filter接口源码

public interface Filter {
  
    /**
     * 过滤器初始化方法,在Web应用启动时调用
     * @param filterConfig 过滤器配置对象
     * @throws ServletException 初始化异常
     */
    default void init(FilterConfig filterConfig) throws ServletException {
    }
  
    /**
     * 过滤器核心方法,处理请求和响应
     * @param request 请求对象
     * @param response 响应对象
     * @param chain 过滤器链
     * @throws IOException IO异常
     * @throws ServletException Servlet异常
     */
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException;
  
    /**
     * 过滤器销毁方法,在Web应用关闭时调用
     */
    default void destroy() {
    }
}

2. FilterChain接口源码

public interface FilterChain {
  
    /**
     * 调用过滤器链中的下一个过滤器
     * 如果没有下一个过滤器,则调用目标资源(Servlet)
     * @param request 请求对象
     * @param response 响应对象
     * @throws IOException IO异常
     * @throws ServletException Servlet异常
     */
    void doFilter(ServletRequest request, ServletResponse response) 
        throws IOException, ServletException;
}

3. FilterConfig接口源码

public interface FilterConfig {
  
    /**
     * 获取过滤器名称
     * @return 过滤器名称
     */
    String getFilterName();
  
    /**
     * 获取ServletContext对象
     * @return ServletContext对象
     */
    ServletContext getServletContext();
  
    /**
     * 获取初始化参数值
     * @param name 参数名
     * @return 参数值
     */
    String getInitParameter(String name);
  
    /**
     * 获取所有初始化参数名
     * @return 参数名枚举
     */
    Enumeration<String> getInitParameterNames();
}

4. ApplicationFilterChain源码分析

public final class ApplicationFilterChain implements FilterChain {
  
    // 过滤器数组
    private ApplicationFilterConfig[] filters;
  
    // 当前执行的过滤器索引
    private int pos = 0;
  
    // 过滤器链中过滤器的数量
    private int n = 0;
  
    // Servlet对象
    private Servlet servlet = null;
  
    // 请求对象
    private Request request = null;
  
    // 响应对象
    private Response response = null;
  
    /**
     * 过滤器链的核心执行方法
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response) 
        throws IOException, ServletException {
      
        // 内部doFilter方法,传递this作为FilterChain
        internalDoFilter(request, response);
    }
  
    /**
     * 内部doFilter方法
     */
    private void internalDoFilter(ServletRequest request, ServletResponse response) 
        throws IOException, ServletException {
      
        // 如果还有过滤器需要执行
        if (pos < n) {
            // 获取当前过滤器
            ApplicationFilterConfig filterConfig = filters[pos++];
            Filter filter = null;
          
            try {
                // 获取过滤器实例
                filter = filterConfig.getFilter();
              
                // 调用过滤器的doFilter方法,传递this作为FilterChain
                filter.doFilter(request, response, this);
              
            } catch (IOException | ServletException | RuntimeException e) {
                // 异常处理
                throw e;
            } catch (Throwable e) {
                // 其他异常包装为ServletException
                throw new ServletException("Filter execution failed", e);
            }
            return;
        }
      
        // 所有过滤器执行完毕,调用Servlet的service方法
        try {
            if (servlet != null) {
                servlet.service(request, response);
            }
        } catch (IOException | ServletException e) {
            throw e;
        } catch (Throwable e) {
            throw new ServletException("Servlet execution failed", e);
        }
    }
}

5. 过滤器执行流程

客户端 过滤器1 过滤器2 过滤器3 Servlet 过滤器链 HTTP请求 前置处理 doFilter() 调用下一个过滤器 前置处理 doFilter() 调用下一个过滤器 前置处理 doFilter() 调用Servlet 处理业务逻辑 返回响应 后置处理 返回 后置处理 返回 后置处理 返回响应 客户端 过滤器1 过滤器2 过滤器3 Servlet 过滤器链

设计模式

1. 责任链模式(Chain of Responsibility)

模式说明

过滤器链是责任链模式的典型应用,每个过滤器都有机会处理请求,并且可以将请求传递给下一个过滤器。

实现分析
// 责任链模式的核心实现
public class ApplicationFilterChain implements FilterChain {
  
    private ApplicationFilterConfig[] filters;
    private int pos = 0;
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response) 
        throws IOException, ServletException {
      
        if (pos < filters.length) {
            // 获取当前过滤器
            ApplicationFilterConfig filterConfig = filters[pos++];
            Filter filter = filterConfig.getFilter();
          
            // 调用当前过滤器,传递this作为下一个处理器
            filter.doFilter(request, response, this);
        } else {
            // 所有过滤器处理完毕,调用目标资源
            servlet.service(request, response);
        }
    }
}
模式优势
  • 解耦: 发送者和接收者解耦
  • 灵活性: 可以动态组合过滤器
  • 扩展性: 新增过滤器不影响现有代码

2. 模板方法模式(Template Method)

模式说明

Filter接口定义了过滤器执行的标准流程,子类通过实现doFilter方法来定义具体的处理逻辑。

实现分析
// 模板方法模式
public interface Filter {
    // 模板方法:定义执行流程
    default void init(FilterConfig filterConfig) throws ServletException {}
  
    // 抽象方法:子类必须实现
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException;
  
    // 模板方法:定义销毁流程
    default void destroy() {}
}

// 具体实现类
public class LoggingFilter implements Filter {
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        // 前置处理
        long startTime = System.currentTimeMillis();
        System.out.println("请求开始时间: " + startTime);
      
        // 调用下一个处理器
        chain.doFilter(request, response);
      
        // 后置处理
        long endTime = System.currentTimeMillis();
        System.out.println("请求处理时间: " + (endTime - startTime) + "ms");
    }
}

3. 装饰器模式(Decorator)

模式说明

过滤器可以对请求和响应进行装饰,添加额外的功能而不改变原有的接口。

实现分析
// 装饰器模式:请求装饰器
public class RequestDecorator extends HttpServletRequestWrapper {
  
    private final HttpServletRequest request;
  
    public RequestDecorator(HttpServletRequest request) {
        super(request);
        this.request = request;
    }
  
    @Override
    public String getParameter(String name) {
        String value = request.getParameter(name);
        // 添加装饰逻辑:参数值过滤
        if (value != null) {
            value = value.replaceAll("<script>", "").replaceAll("</script>", "");
        }
        return value;
    }
}

// 装饰器模式:响应装饰器
public class ResponseDecorator extends HttpServletResponseWrapper {
  
    private final HttpServletResponse response;
  
    public ResponseDecorator(HttpServletResponse response) {
        super(response);
        this.response = response;
    }
  
    @Override
    public PrintWriter getWriter() throws IOException {
        // 添加装饰逻辑:响应内容压缩
        return new PrintWriter(new GZIPOutputStream(response.getOutputStream()));
    }
}

4. 策略模式(Strategy)

模式说明

不同的过滤器实现不同的处理策略,可以根据配置动态选择使用哪个过滤器。

实现分析
// 策略接口
public interface FilterStrategy {
    void process(HttpServletRequest request, HttpServletResponse response);
}

// 具体策略:日志记录
public class LoggingStrategy implements FilterStrategy {
    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("记录请求日志: " + request.getRequestURI());
    }
}

// 具体策略:权限验证
public class AuthStrategy implements FilterStrategy {
    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader("Authorization");
        if (token == null || !validateToken(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        }
    }
}

// 策略上下文
public class FilterContext {
    private FilterStrategy strategy;
  
    public void setStrategy(FilterStrategy strategy) {
        this.strategy = strategy;
    }
  
    public void execute(HttpServletRequest request, HttpServletResponse response) {
        strategy.process(request, response);
    }
}

5. 工厂模式(Factory)

模式说明

FilterConfig负责创建和管理过滤器实例,这是工厂模式的应用。

实现分析
// 过滤器工厂
public class FilterFactory {
  
    private static final Map<String, Filter> filterCache = new ConcurrentHashMap<>();
  
    public static Filter createFilter(String filterClassName) throws Exception {
        // 先从缓存中获取
        Filter filter = filterCache.get(filterClassName);
        if (filter != null) {
            return filter;
        }
      
        // 通过反射创建实例
        Class<?> filterClass = Class.forName(filterClassName);
        filter = (Filter) filterClass.newInstance();
      
        // 放入缓存
        filterCache.put(filterClassName, filter);
      
        return filter;
    }
}

// 在FilterConfig中的应用
public class ApplicationFilterConfig implements FilterConfig {
  
    private final Filter filter;
  
    public ApplicationFilterConfig(String filterClassName) throws Exception {
        // 使用工厂创建过滤器实例
        this.filter = FilterFactory.createFilter(filterClassName);
    }
  
    public Filter getFilter() {
        return filter;
    }
}

项目应用场景

1. 身份认证和授权

场景描述

在Web应用中,需要对用户进行身份验证和权限控制,确保只有授权用户才能访问特定资源。

实现示例
@WebFilter(urlPatterns = "/*")
public class AuthenticationFilter implements Filter {
  
    private static final Set<String> PUBLIC_URLS = Set.of(
        "/login", "/register", "/public", "/static", "/css", "/js", "/images"
    );
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
      
        String requestURI = httpRequest.getRequestURI();
      
        // 检查是否为公开URL
        if (isPublicUrl(requestURI)) {
            chain.doFilter(request, response);
            return;
        }
      
        // 检查用户是否已登录
        HttpSession session = httpRequest.getSession(false);
        if (session == null || session.getAttribute("user") == null) {
            // 重定向到登录页面
            httpResponse.sendRedirect(httpRequest.getContextPath() + "/login");
            return;
        }
      
        // 检查用户权限
        User user = (User) session.getAttribute("user");
        if (!hasPermission(user, requestURI)) {
            httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
            return;
        }
      
        // 继续执行过滤器链
        chain.doFilter(request, response);
    }
  
    private boolean isPublicUrl(String uri) {
        return PUBLIC_URLS.stream().anyMatch(uri::startsWith);
    }
  
    private boolean hasPermission(User user, String uri) {
        // 根据用户角色和权限检查是否有访问权限
        return user.getRoles().stream()
            .anyMatch(role -> role.hasPermission(uri));
    }
}

2. 请求日志记录

场景描述

记录所有HTTP请求的详细信息,包括请求时间、处理时间、请求参数等,用于系统监控和问题排查。

实现示例
@WebFilter(urlPatterns = "/*")
public class LoggingFilter implements Filter {
  
    private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
      
        // 记录请求开始时间
        long startTime = System.currentTimeMillis();
      
        // 记录请求信息
        String requestURI = httpRequest.getRequestURI();
        String method = httpRequest.getMethod();
        String remoteAddr = httpRequest.getRemoteAddr();
        String userAgent = httpRequest.getHeader("User-Agent");
      
        logger.info("请求开始 - URI: {}, Method: {}, RemoteAddr: {}, UserAgent: {}", 
            requestURI, method, remoteAddr, userAgent);
      
        try {
            // 继续执行过滤器链
            chain.doFilter(request, response);
          
            // 记录响应信息
            int status = httpResponse.getStatus();
            long duration = System.currentTimeMillis() - startTime;
          
            logger.info("请求完成 - URI: {}, Status: {}, Duration: {}ms", 
                requestURI, status, duration);
          
        } catch (Exception e) {
            // 记录异常信息
            long duration = System.currentTimeMillis() - startTime;
            logger.error("请求异常 - URI: {}, Duration: {}ms, Error: {}", 
                requestURI, duration, e.getMessage(), e);
            throw e;
        }
    }
}

3. 字符编码处理

场景描述

统一处理请求和响应的字符编码,避免中文乱码问题。

实现示例
@WebFilter(urlPatterns = "/*")
public class CharacterEncodingFilter implements Filter {
  
    private String encoding = "UTF-8";
    private boolean forceEncoding = true;
  
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String encodingParam = filterConfig.getInitParameter("encoding");
        if (encodingParam != null) {
            this.encoding = encodingParam;
        }
      
        String forceEncodingParam = filterConfig.getInitParameter("forceEncoding");
        if (forceEncodingParam != null) {
            this.forceEncoding = Boolean.parseBoolean(forceEncodingParam);
        }
    }
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        // 设置请求编码
        if (this.forceEncoding || request.getCharacterEncoding() == null) {
            request.setCharacterEncoding(this.encoding);
        }
      
        // 设置响应编码
        if (this.forceEncoding || response.getCharacterEncoding() == null) {
            response.setCharacterEncoding(this.encoding);
        }
      
        // 继续执行过滤器链
        chain.doFilter(request, response);
    }
}

4. 跨域请求处理

场景描述

处理跨域请求,设置必要的CORS头部信息,允许不同域名的客户端访问API。

实现示例
@WebFilter(urlPatterns = "/*")
public class CorsFilter implements Filter {
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        HttpServletResponse httpResponse = (HttpServletResponse) response;
      
        // 设置CORS头部
        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
        httpResponse.setHeader("Access-Control-Max-Age", "3600");
      
        // 处理预检请求
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {
            httpResponse.setStatus(HttpServletResponse.SC_OK);
            return;
        }
      
        // 继续执行过滤器链
        chain.doFilter(request, response);
    }
}

5. 请求限流

场景描述

对API请求进行限流控制,防止恶意攻击和系统过载。

实现示例
@WebFilter(urlPatterns = "/api/*")
public class RateLimitFilter implements Filter {
  
    private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();
    private final int maxRequestsPerMinute = 100;
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String clientIp = getClientIp(httpRequest);
      
        // 获取或创建限流器
        RateLimiter limiter = limiters.computeIfAbsent(clientIp, 
            k -> RateLimiter.create(maxRequestsPerMinute / 60.0)); // 每秒允许的请求数
      
        // 尝试获取令牌
        if (!limiter.tryAcquire()) {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
            httpResponse.getWriter().write("请求过于频繁,请稍后再试");
            return;
        }
      
        // 继续执行过滤器链
        chain.doFilter(request, response);
    }
  
    private String getClientIp(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0].trim();
        }
        return request.getRemoteAddr();
    }
}

6. 响应压缩

场景描述

对响应内容进行压缩,减少网络传输量,提高页面加载速度。

实现示例
@WebFilter(urlPatterns = "/*")
public class CompressionFilter implements Filter {
  
    private static final Set<String> COMPRESSIBLE_TYPES = Set.of(
        "text/html", "text/xml", "text/plain", "text/css", "text/javascript",
        "application/json", "application/xml", "application/javascript"
    );
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
      
        // 检查是否支持压缩
        String acceptEncoding = httpRequest.getHeader("Accept-Encoding");
        if (acceptEncoding == null || !acceptEncoding.contains("gzip")) {
            chain.doFilter(request, response);
            return;
        }
      
        // 检查内容类型是否可压缩
        String contentType = httpResponse.getContentType();
        if (contentType == null || !isCompressible(contentType)) {
            chain.doFilter(request, response);
            return;
        }
      
        // 创建压缩响应包装器
        GZIPResponseWrapper gzipResponse = new GZIPResponseWrapper(httpResponse);
      
        try {
            // 继续执行过滤器链
            chain.doFilter(request, gzipResponse);
        } finally {
            // 完成压缩
            gzipResponse.finish();
        }
    }
  
    private boolean isCompressible(String contentType) {
        return COMPRESSIBLE_TYPES.stream().anyMatch(contentType::contains);
    }
}

// GZIP响应包装器
class GZIPResponseWrapper extends HttpServletResponseWrapper {
  
    private GZIPOutputStream gzipOutputStream;
    private PrintWriter printWriter;
  
    public GZIPResponseWrapper(HttpServletResponse response) {
        super(response);
    }
  
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (gzipOutputStream == null) {
            gzipOutputStream = new GZIPOutputStream(getResponse().getOutputStream());
        }
        return new ServletOutputStream() {
            @Override
            public boolean isReady() {
                return true;
            }
          
            @Override
            public void setWriteListener(WriteListener writeListener) {
            }
          
            @Override
            public void write(int b) throws IOException {
                gzipOutputStream.write(b);
            }
        };
    }
  
    @Override
    public PrintWriter getWriter() throws IOException {
        if (printWriter == null) {
            printWriter = new PrintWriter(new OutputStreamWriter(gzipOutputStream, "UTF-8"));
        }
        return printWriter;
    }
  
    public void finish() throws IOException {
        if (printWriter != null) {
            printWriter.close();
        }
        if (gzipOutputStream != null) {
            gzipOutputStream.close();
        }
    }
}

面试高频点

1. 基础概念

Q1: 什么是Java过滤器?它的作用是什么?

A:

  • 定义: Java过滤器是Java Web应用中的一个组件,用于在请求到达Servlet之前和响应返回客户端之前进行预处理和后处理
  • 作用:
    • 请求拦截和预处理
    • 响应后处理
    • 身份认证和授权
    • 日志记录
    • 字符编码处理
    • 跨域处理等
Q2: 过滤器的生命周期是什么?

A:

// 过滤器生命周期
public class MyFilter implements Filter {
  
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 1. 初始化阶段:Web应用启动时调用一次
        // 用于初始化过滤器资源
    }
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
        // 2. 过滤阶段:每次请求都会调用
        // 前置处理
        chain.doFilter(request, response);
        // 后置处理
    }
  
    @Override
    public void destroy() {
        // 3. 销毁阶段:Web应用关闭时调用一次
        // 用于释放过滤器资源
    }
}
Q3: 过滤器链的执行顺序是怎样的?

A:

  • 执行顺序: 按照web.xml中配置的顺序,或者@WebFilter注解的order属性值
  • 执行流程:
    1. 过滤器1前置处理 → 过滤器2前置处理 → … → Servlet处理 → 过滤器N后置处理 → … → 过滤器1后置处理
  • 关键点: 前置处理按顺序执行,后置处理按逆序执行

2. 配置和实现

Q4: 如何配置过滤器?有哪些配置方式?

A:

// 方式1: 注解配置
@WebFilter(
    urlPatterns = "/*",
    filterName = "myFilter",
    initParams = {
        @WebInitParam(name = "encoding", value = "UTF-8")
    },
    order = 1
)
public class MyFilter implements Filter {
    // 过滤器实现
}

// 方式2: web.xml配置
<filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.example.MyFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
Q5: 如何实现一个自定义过滤器?

A:

public class CustomFilter implements Filter {
  
    private String filterName;
  
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterName = filterConfig.getFilterName();
        System.out.println("过滤器 " + filterName + " 初始化完成");
    }
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
      
        // 前置处理
        System.out.println("过滤器 " + filterName + " 开始处理请求: " + httpRequest.getRequestURI());
      
        // 调用下一个过滤器或Servlet
        chain.doFilter(request, response);
      
        // 后置处理
        System.out.println("过滤器 " + filterName + " 完成处理请求: " + httpRequest.getRequestURI());
    }
  
    @Override
    public void destroy() {
        System.out.println("过滤器 " + filterName + " 销毁完成");
    }
}

3. 高级特性

Q6: 过滤器与拦截器的区别是什么?

A:

对比项 Filter Interceptor
实现方式 基于函数回调 基于反射机制
使用范围 只能用于Web应用 可以用于Web应用、Spring应用等
获取资源 只能获取ServletContext 可以获取Spring容器中的资源
执行顺序 在Interceptor之前执行 在Filter之后执行
异常处理 不能使用Spring的异常处理机制 可以使用Spring的异常处理机制
Q7: 如何实现过滤器的动态配置?

A:

public class DynamicFilter implements Filter {
  
    private volatile FilterConfig filterConfig;
    private volatile Map<String, String> dynamicParams = new ConcurrentHashMap<>();
  
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        // 加载初始配置
        loadDynamicParams();
    }
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        // 动态获取配置参数
        String maxRequests = getDynamicParam("maxRequests", "100");
        String timeWindow = getDynamicParam("timeWindow", "60");
      
        // 根据动态配置执行逻辑
        // ...
      
        chain.doFilter(request, response);
    }
  
    private String getDynamicParam(String key, String defaultValue) {
        return dynamicParams.getOrDefault(key, defaultValue);
    }
  
    private void loadDynamicParams() {
        // 从数据库或配置文件加载动态参数
        // 可以通过定时任务或事件驱动方式更新
    }
  
    // 提供动态更新配置的方法
    public void updateConfig(String key, String value) {
        dynamicParams.put(key, value);
    }
}

4. 性能优化

Q8: 如何优化过滤器的性能?

A:

public class OptimizedFilter implements Filter {
  
    // 1. 使用缓存减少重复计算
    private final Map<String, Object> cache = new ConcurrentHashMap<>();
  
    // 2. 使用线程安全的集合
    private final Set<String> excludeUrls = ConcurrentHashMap.newKeySet();
  
    // 3. 避免在doFilter中创建大量对象
    private final ThreadLocal<SimpleDateFormat> dateFormat = 
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();
      
        // 4. 快速路径:排除不需要处理的URL
        if (excludeUrls.contains(requestURI)) {
            chain.doFilter(request, response);
            return;
        }
      
        // 5. 使用缓存减少重复计算
        String cacheKey = "auth_" + requestURI;
        Boolean isAuthorized = (Boolean) cache.get(cacheKey);
        if (isAuthorized == null) {
            isAuthorized = checkAuthorization(httpRequest, requestURI);
            cache.put(cacheKey, isAuthorized);
        }
      
        if (!isAuthorized) {
            ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_FORBIDDEN);
            return;
        }
      
        chain.doFilter(request, response);
    }
  
    private boolean checkAuthorization(HttpServletRequest request, String uri) {
        // 权限检查逻辑
        return true;
    }
}
Q9: 如何处理过滤器中的异常?

A:

public class ExceptionHandlingFilter implements Filter {
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        try {
            // 执行过滤器逻辑
            chain.doFilter(request, response);
          
        } catch (AuthenticationException e) {
            // 处理认证异常
            handleAuthenticationException((HttpServletResponse) response, e);
          
        } catch (AuthorizationException e) {
            // 处理授权异常
            handleAuthorizationException((HttpServletResponse) response, e);
          
        } catch (Exception e) {
            // 处理其他异常
            handleGenericException((HttpServletResponse) response, e);
        }
    }
  
    private void handleAuthenticationException(HttpServletResponse response, AuthenticationException e) 
        throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("{\"error\":\"认证失败\",\"message\":\"" + e.getMessage() + "\"}");
    }
  
    private void handleAuthorizationException(HttpServletResponse response, AuthorizationException e) 
        throws IOException {
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("{\"error\":\"权限不足\",\"message\":\"" + e.getMessage() + "\"}");
    }
  
    private void handleGenericException(HttpServletResponse response, Exception e) 
        throws IOException {
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("{\"error\":\"系统异常\",\"message\":\"请稍后重试\"}");
      
        // 记录日志
        logger.error("过滤器执行异常", e);
    }
}

5. 实际应用

Q10: 在Spring Boot中如何使用过滤器?

A:

// 方式1: 实现Filter接口
@Component
public class SpringBootFilter implements Filter {
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
        // 过滤器逻辑
        chain.doFilter(request, response);
    }
}

// 方式2: 使用FilterRegistrationBean配置
@Configuration
public class FilterConfig {
  
    @Bean
    public FilterRegistrationBean<MyFilter> myFilterRegistration() {
        FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new MyFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(1);
        registration.setName("myFilter");
        return registration;
    }
}

// 方式3: 使用@WebFilter注解
@WebFilter(urlPatterns = "/*")
public class WebFilter implements Filter {
    // 过滤器实现
}

最佳实践

1. 过滤器设计原则

// 单一职责原则:每个过滤器只负责一个功能
public class AuthenticationFilter implements Filter {
    // 只负责身份认证
}

public class LoggingFilter implements Filter {
    // 只负责日志记录
}

public class EncodingFilter implements Filter {
    // 只负责字符编码
}

// 开闭原则:对扩展开放,对修改关闭
public abstract class AbstractFilter implements Filter {
  
    protected abstract void doPreFilter(HttpServletRequest request, HttpServletResponse response);
    protected abstract void doPostFilter(HttpServletRequest request, HttpServletResponse response);
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
      
        // 前置处理
        doPreFilter(httpRequest, httpResponse);
      
        // 继续执行过滤器链
        chain.doFilter(request, response);
      
        // 后置处理
        doPostFilter(httpRequest, httpResponse);
    }
}

2. 性能优化实践

public class PerformanceOptimizedFilter implements Filter {
  
    // 使用缓存减少重复计算
    private final LoadingCache<String, Boolean> permissionCache = Caffeine.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(5, TimeUnit.MINUTES)
        .build(key -> checkPermission(key));
  
    // 使用线程池处理异步任务
    private final ExecutorService executorService = Executors.newFixedThreadPool(10);
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();
      
        // 异步记录访问日志
        executorService.submit(() -> logAccess(requestURI));
      
        // 使用缓存检查权限
        String cacheKey = getCacheKey(httpRequest);
        Boolean hasPermission = permissionCache.get(cacheKey);
      
        if (!hasPermission) {
            ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_FORBIDDEN);
            return;
        }
      
        chain.doFilter(request, response);
    }
  
    private String getCacheKey(HttpServletRequest request) {
        return request.getRemoteAddr() + ":" + request.getRequestURI();
    }
  
    private boolean checkPermission(String key) {
        // 权限检查逻辑
        return true;
    }
  
    private void logAccess(String uri) {
        // 异步记录访问日志
        logger.info("访问URI: {}", uri);
    }
}

3. 异常处理实践

public class RobustFilter implements Filter {
  
    private static final Logger logger = LoggerFactory.getLogger(RobustFilter.class);
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
      
        try {
            // 前置处理
            doPreProcess(request, response);
          
            // 执行过滤器链
            chain.doFilter(request, response);
          
            // 后置处理
            doPostProcess(request, response);
          
        } catch (Exception e) {
            // 异常处理
            handleException(request, response, e);
        }
    }
  
    private void doPreProcess(ServletRequest request, ServletResponse response) {
        // 前置处理逻辑
    }
  
    private void doPostProcess(ServletRequest request, ServletResponse response) {
        // 后置处理逻辑
    }
  
    private void handleException(ServletRequest request, ServletResponse response, Exception e) {
        logger.error("过滤器执行异常", e);
      
        // 根据异常类型进行不同处理
        if (e instanceof SecurityException) {
            handleSecurityException(response, (SecurityException) e);
        } else if (e instanceof IllegalArgumentException) {
            handleIllegalArgumentException(response, (IllegalArgumentException) e);
        } else {
            handleGenericException(response, e);
        }
    }
  
    private void handleSecurityException(ServletResponse response, SecurityException e) {
        // 处理安全异常
        try {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
            httpResponse.getWriter().write("访问被拒绝");
        } catch (IOException ex) {
            logger.error("写入响应失败", ex);
        }
    }
  
    private void handleIllegalArgumentException(ServletResponse response, IllegalArgumentException e) {
        // 处理参数异常
        try {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            httpResponse.getWriter().write("请求参数错误");
        } catch (IOException ex) {
            logger.error("写入响应失败", ex);
        }
    }
  
    private void handleGenericException(ServletResponse response, Exception e) {
        // 处理通用异常
        try {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            httpResponse.getWriter().write("系统内部错误");
        } catch (IOException ex) {
            logger.error("写入响应失败", ex);
        }
    }
}

总结

1. 学习路径图

Java过滤器学习
基础阶段
进阶阶段
高级阶段
实战应用
Filter接口理解
生命周期管理
基本配置方式
过滤器链机制
设计模式应用
源码深度分析
性能优化
异常处理
动态配置
身份认证
日志记录
跨域处理
请求限流

2. 核心优势

优势 说明
请求拦截 在请求到达Servlet之前进行拦截和处理
响应处理 在响应返回客户端之前进行处理
链式调用 多个过滤器可以组成过滤器链,按顺序执行
生命周期管理 由容器管理,随Web应用启动而创建,随应用关闭而销毁
配置灵活 支持注解配置和web.xml配置两种方式

3. 适用场景

场景 说明
身份认证 用户登录验证、权限控制
日志记录 请求日志、访问统计
字符编码 统一处理请求和响应编码
跨域处理 设置CORS头部信息
请求限流 防止恶意攻击和系统过载
响应压缩 减少网络传输量

4. 注意事项

注意点 说明
执行顺序 注意过滤器的执行顺序,前置处理按顺序,后置处理按逆序
异常处理 合理处理过滤器中的异常,避免影响正常业务流程
性能考虑 避免在过滤器中执行耗时操作,合理使用缓存
资源管理 及时释放过滤器占用的资源,避免内存泄漏

5. 学习建议

通过系统学习Java过滤器,可以:

  • 理解Web架构 - 深入理解Web应用的请求处理流程
  • 掌握设计模式 - 学习责任链、装饰器等设计模式的实际应用
  • 提升开发能力 - 掌握Web应用开发中的常见问题解决方案
  • 增强系统性能 - 学会使用过滤器优化系统性能

实践建议: 在实际项目中多应用过滤器技术,通过实践加深理解,逐步掌握其高级特性和最佳实践。记住:过滤器是Web应用的重要基础设施,合理使用可以大大提升系统的健壮性和性能

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐