在现代Web开发中,安全性和性能是至关重要的因素。过滤器和拦截器是Web应用中的两个关键概念,它们可以帮助你保护你的应用免受恶意攻击,同时还可以实现各种功能,从日志记录到性能优化。这两个概念可能听起来有些抽象,但实际上它们就像是你应用的护卫者,站在前线,确保一切都在掌握之中。在本文中,我们将深入探讨过滤器和拦截器的作用、差异以及如何在你的项目中充分利用它们。
拦截器和过滤器都使用了AOP的编程思想,都可以实现诸如日志记录、登录鉴权等功能,但二者的不同点也是比较多的
过滤器(Filters)和拦截器(Interceptors)是在Web开发中用于处理HTTP请求和响应的关键组件,它们用于执行一些特定的任务,如请求预处理、响应处理、日志记录、安全验证等。以下是它们的基本介绍以及在Web开发中的角色:
过滤器(Filters):
拦截器(Interceptors):
区别和选择:
拦截器和过滤器底层实现方式大不相同,过滤器是基于函数回调的,拦截器则是基于java的反射机制(动态代理)实现的。
我们自定义的过滤器中都会实现一个doFIlter()方法,这个方法有一个FilterChain参数,而实际上它是一个回调接口。Application FilterChain是它的实现类,这个实现类内部也有一个doFilter()方法就是回调方法。
public interface FilterChain {
void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
ApplicationFilterChain里面能拿到我们自定义的xxxFilter类,在其内部回调方法doFilter()里面调用各个自定义xxxFilter过滤器,并执行doFilter()方法
public final class ApplicationFilterChain implements FilterChain {
@Override
public void doFilter(ServletRequest request, ServletResponse response) {
...//省略
internalDoFilter(request,response);
}
private void internalDoFilter(ServletRequest request, ServletResponse response){
if (pos < n) {
//获取第pos个filter
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = filterConfig.getFilter();
...
filter.doFilter(request, response, this);
}
}
}
每个xxxFilter会先执行自身的doFilter()过滤逻辑,最后在执行结束前会执行filterChain.doFilter(servletRequest,servletResponse),也就是回调Application FilterChain的doFilter()方法,以此循环执行实现函数回调。
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest, servletResponse);
}
我们看到过滤器实现的是javax.servlet.Filter接口,而这个接口是在servlet规范中定义的,也就是说过滤器Filter的使用要依赖于Tomcat等容器,导致它只能在web程序中用。
而拦截器(Interceptor)它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器。是可以单独使用的。不仅能应用在web程序汇总,也可以用于Application、Swing等程序中。
过滤器(Filters)和拦截器(Interceptors)在使用范围上有一些不同,这取决于它们所属的技术框架以及其执行的阶段和任务。以下是它们的使用范围的不同之处:
过滤器(Filters)的使用范围:
Servlet容器级别:过滤器是Servlet规范的一部分,因此它们在Servlet容器级别操作。这意味着它们可以应用于任何基于Servlet的Web应用程序,不依赖于特定的框架。
低级别任务:过滤器通常用于处理HTTP请求和响应的低级别任务,如字符编码、缓存控制、压缩、请求参数处理等。它们可以修改请求和响应的底层内容。
全局性处理:过滤器能够对整个Web应用程序的请求和响应进行全局性处理,因此可以应用于多个URL模式下的请求。
拦截器(Interceptors)的使用范围:
Spring MVC框架级别:拦截器是Spring MVC框架的一部分,因此它们在Spring应用程序中使用。拦截器只对Spring MVC控制器处理的请求生效。
高级别任务:拦截器通常用于处理与业务逻辑相关的高级别任务,如权限验证、日志记录、性能监测、国际化、异常处理等。它们更专注于业务逻辑。
控制器级别处理:拦截器只拦截Spring MVC控制器处理的请求,因此可以根据需要选择性地应用于特定的控制器或URL模式。
总结:
过滤器和拦截器的触发时机也不同,如下图
过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后
拦截器Interceptor是在请求进入servlet后,在进入Controller之前进行预处理的,Controller中渲染了对应的视图之后请求结束。
在Spring Boot应用程序中,使用过滤器(Filters)和拦截器(Interceptors)时,注入Bean的方式有一些不同,这取决于它们所属的技术框架和生命周期管理。以下是过滤器和拦截器注入Bean的不同之处:
过滤器(Filters)的注入Bean:
过滤器是Servlet规范的一部分,它们通常不是由Spring容器管理的Bean。因此,过滤器的生命周期由Servlet容器管理,而不是Spring容器。
你不能直接使用Spring的依赖注入(如@Autowired
)来注入其他Spring Bean到过滤器中,因为过滤器实例通常不受Spring的控制。
为了在过滤器中使用Spring的Bean,你可以通过Spring的WebApplicationContextUtils
工具类获取ApplicationContext
,然后从中获取所需的Bean。
示例代码:
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class MyFilter implements Filter {
private MyService myService;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
ApplicationContext context = WebApplicationContextUtils
.getRequiredWebApplicationContext(filterConfig.getServletContext());
myService = context.getBean(MyService.class);
}
// ...
}
拦截器(Interceptors)的注入Bean:
拦截器是Spring MVC框架的一部分,它们通常是由Spring容器管理的Bean。因此,你可以直接使用Spring的依赖注入来注入其他Spring Bean到拦截器中。
你可以使用@Autowired
或@Resource
等注解将其他Spring Bean注入到拦截器中,这使得在拦截器中使用Spring管理的服务和组件变得非常方便。
示例代码:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class MyInterceptor implements HandlerInterceptor {
private MyService myService;
@Autowired
public MyInterceptor(MyService myService) {
this.myService = myService;
}
// ...
}
总结:
WebApplicationContextUtils
等方式来手动获取Spring容器中的Bean。@Autowired
)来注入其他Spring Bean 到拦截器中,这更加便捷。理解过滤器和拦截器的差异,让我们以一个基于Spring Boot的用户认证示例为例,展示如何使用过滤器和拦截器来实现用户认证。
场景:我们将创建一个Spring Boot Web应用程序,其中包含一个受保护的资源,只有已登录的用户才能访问。我们将使用过滤器和拦截器分别来实现这个认证逻辑。
项目设置:首先,确保你有一个Spring Boot项目的基础设置。
使用过滤器的示例:
AuthenticationFilter
,来检查用户是否已登录。import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
public class AuthenticationFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 在这里检查用户是否已登录,例如从Session中获取用户信息
// 如果用户未登录,可以重定向到登录页面
// 如果用户已登录,允许请求继续执行
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化过滤器(可选)
}
@Override
public void destroy() {
// 销毁过滤器(可选)
}
}
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<AuthenticationFilter> authenticationFilter() {
FilterRegistrationBean<AuthenticationFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new AuthenticationFilter());
// 设置需要过滤的URL模式
registrationBean.addUrlPatterns("/protected/*"); // 这里假设受保护的资源在/protected/下
return registrationBean;
}
}
使用拦截器的示例:
AuthenticationInterceptor
,来检查用户是否已登录。import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 在这里检查用户是否已登录,例如从Session中获取用户信息
// 如果用户未登录,可以重定向到登录页面
// 如果用户已登录,返回true允许请求继续执行,或者返回false阻止请求继续执行
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 请求处理后执行的操作(可选)
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
// 完成请求后执行的操作(可选)
}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthenticationInterceptor())
.addPathPatterns("/protected/**"); // 这里假设受保护的资源在/protected/下
}
}
在上述示例中,无论你选择使用过滤器还是拦截器,它们都用于拦截请求并执行用户认证逻辑。关于具体的用户认证逻辑(例如如何检查用户是否已登录),需要根据你的应用程序和需求来实现。