目录
一、过滤器(Filter)
1.概念
-
过滤器是Servlet容器提供的一个标准接口,用于对进入或离开容器的HTTP请求和响应进行预处理和后处理。过滤器可以检查、修改或终止请求和响应。
-
在Spring Boot中,可以通过实现javax.servlet.Filter接口并配置FilterRegistrationBean来使用过滤器。
2.实现方式
-
实现javax.servlet.Filter接口。
-
需要在web.xml中配置过滤器,或者在Spring框架中使用@WebFilter注解。
-
重写init()、doFilter()和destroy()方法。
Java Servlet Filter 示例
import javax.servlet.*;
import java.io.IOException;
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("Filter before processing");
chain.doFilter(request, response);
System.out.println("Filter after processing");
}
@Override
public void destroy() {}
}
3.解决的问题
-
安全性:例如,实现一个过滤器来检查用户是否已经登录。
-
日志记录:记录所有请求和响应的信息。
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class AuthenticationFilter implements javax.servlet.Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 检查用户是否已登录
if (httpRequest.getSession().getAttribute("user") != null) {
chain.doFilter(request, response); // 请求继续
} else {
((HttpServletResponse) response).sendRedirect("/login"); // 重定向到登录页面
}
}
}
// Spring Boot配置
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 authenticationFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new AuthenticationFilter());
registration.addUrlPatterns("/*"); // 应用于所有URL
return registration;
}
}
二、拦截器(Interceptor)
1.概念
-
拦截器通常在MVC框架中使用,用于在控制器方法执行前后进行拦截,可以做日志记录、事务管理、权限校验等。
2.实现方式
-
实现org.springframework.web.servlet.HandlerInterceptor接口或继承HandlerInterceptorAdapter类。
-
需要在Spring配置文件中注册拦截器,或者使用@ControllerAdvice配合@ModelAttribute、@ExceptionHandler等注解。
-
重写preHandle()、postHandle()和afterCompletion()方法。
Spring MVC Interceptor 示例
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Interceptor before processing");
return true; // 返回false表示停止后续处理
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor after completion");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Interceptor after completion with exception");
}
}
3.解决的问题
-
日志记录:记录控制器方法的调用。
-
权限检查:确保用户有访问特定资源的权限。
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoggingInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("LoggingInterceptor: Request received for URL: " + request.getRequestURL());
return true; // 允许请求继续
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("LoggingInterceptor: Request processed.");
}
}
// Spring Boot配置
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 LoggingInterceptor()).addPathPatterns("/**");
}
}
三、切面(Aspect)
1.概念
-
切面是AOP(面向切面编程)中的概念,用于在不修改原始代码的情况下增加额外的行为,如日志记录、性能监控等。
2.实现方式
-
使用AspectJ语言编写切面,或者在Spring框架中使用@Aspect注解标记切面类。
-
定义切点(pointcut)来指定哪些连接点(join point)会被切面所影响。
-
使用@Before、@After、@Around等注解来定义通知(advice)。
Spring AOP Aspect 示例
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MyAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Aspect before processing");
Object result = joinPoint.proceed();
System.out.println("Aspect after processing");
return result;
}
}
3.解决的问题
-
性能监控:记录方法执行的时间。
-
事务管理:自动管理数据库事务。
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class PerformanceAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
return joinPoint.proceed(); // 继续执行方法
} finally {
long elapsedTime = System.currentTimeMillis() - start;
System.out.println("Method " + joinPoint.getSignature() + " took " + elapsedTime + " ms to execute.");
}
}
}
四、监听器(Listener)
1.概念
-
监听器用于监听和响应特定事件,如应用程序上下文初始化、会话创建或销毁等。
2.实现方式
-
实现相应的监听器接口,如ServletContextListener、HttpSessionListener等。
-
需要在web.xml中配置监听器,或者在Spring框架中使用@Component注解。
-
重写相应的事件处理方法,如contextInitialized()、contextDestroyed()等。
3.解决的问题
-
初始化:在应用程序启动时加载配置或数据。
Spring Boot Listener 示例
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
public class MyListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("Listener triggered on context refresh");
}
}
五、代码中的的执行顺序
一般来说,执行顺序如下:
-
过滤器:在请求到达Servlet之前执行。
-
拦截器:在控制器方法执行前后执行。
-
切面:在方法调用的前后执行,具体取决于切点定义。
-
监听器:在特定事件发生时执行,如应用上下文初始化。
六、联系和区别
-
联系:它们都可以用于在应用程序的不同层次中增加横切关注点。
-
区别:它们作用的范围和时机不同:
-
过滤器作用于Servlet容器级别;
-
拦截器作用于MVC框架内;
-
切面作用于方法调用级别;
-
而监听器作用于事件驱动的场景。
-
七、具体的应用场景
假设:实现一个简单的用户认证系统,其中包含登录、日志记录和资源访问控制。
场景描述
-
在一个Web应用中,我们需要确保只有经过认证的用户才能访问特定的资源。此外,我们还需要记录用户的登录尝试和资源访问行为,同时在应用启动时初始化一些全局配置。
解决方案
-
使用Spring框架来实现这个系统,利用过滤器、拦截器、切面和监听器来处理不同的功能。
1. 过滤器(Filter): 用户登录验证
过滤器用于在请求到达应用前进行预处理,这里我们用它来验证用户的登录状态。
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class AuthFilter implements Filter {
// 初始化过滤器,通常用于加载配置信息
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化逻辑
}
/**
* 当请求到达时,此方法被调用。
* 我们在这里检查用户是否已登录。
* 如果未登录,则重定向到登录页面。
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 将请求和响应强制转换为Http类型
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 获取session
HttpSession session = req.getSession(false);
// 检查session中是否有用户信息
if (session != null && session.getAttribute("user") != null) {
// 如果用户已登录,继续处理请求
chain.doFilter(req, res);
} else {
// 如果用户未登录,重定向到登录页面
res.sendRedirect("/login");
}
}
// 销毁过滤器,释放资源
@Override
public void destroy() {
// 销毁逻辑
}
}
2.拦截器(Interceptor): 日志记录
拦截器用于在控制器方法执行前后进行拦截,这里我们用它来记录用户的请求信息。
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoggingInterceptor implements HandlerInterceptor {
/**
* 在控制器方法执行前调用。
* 可以在此处记录请求信息。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("LoggingInterceptor: Request received for URL: " + request.getRequestURL());
return true; // 返回true表示继续处理请求
}
/**
* 在控制器方法执行后,视图渲染前调用。
* 可以在此处记录控制器方法的处理结果。
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("LoggingInterceptor: Request processed.");
}
/**
* 在整个请求处理结束后调用。
* 可以在此处记录请求的最终结果。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("LoggingInterceptor: Request completed.");
}
}
3.切面(Aspect): 资源访问控制
切面用于在方法调用的前后执行额外的逻辑,这里我们用它来检查用户是否有访问特定资源的权限。
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AccessControlAspect {
/**
* 定义一个环绕通知,用于在所有控制器方法调用前后执行。
* 在这里我们可以检查用户是否有访问特定资源的权限。
*/
@Around("execution(* com.example.controller.*.*(..))")
public Object checkAccess(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = (HttpServletRequest) joinPoint.getArgs()[0];
// 检查用户是否有访问当前资源的权限
if (!hasAccess(request)) {
throw new SecurityException("Access denied");
}
// 继续执行原方法
return joinPoint.proceed();
}
/**
* 模拟一个权限检查方法。
* 在实际应用中,这里应该有更复杂的逻辑。
*/
private boolean hasAccess(HttpServletRequest request) {
// 简化处理,假设所有请求都允许访问
return true;
}
}
4.监听器(Listener): 应用启动时的初始化
-
监听器用于监听和响应特定事件,这里我们用它来在应用启动时加载一些配置。
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
public class ConfigInitializationListener implements ApplicationListener<ContextRefreshedEvent> {
/**
* 当Spring应用上下文初始化完成时,此方法被调用。
* 在这里可以加载配置信息或执行任何一次性的初始化任务。
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("ConfigInitializationListener: Application started, loading configurations...");
// 加载配置信息
}
}