SpringBoot 监听器/过滤器/拦截器
一、监听器
1. 使用场景:在一些业务场景中,当容器初始化完成之后,需要处理一些操作,比如一些数据的加载、初始化缓存、特定任务的注册、开启线程或程序来干某些事情等等。
2. 使用步骤
A. 监听类实现ApplicationListener
接口 ;
B. 将监听类添加到SpringApplication
实例(两种方式:application.properties配置、java启动配置)。
3. 事件类型
A. ApplicationStartingEvent:SpringBoot启动开始时执行的事件;
B. ApplicationEnvironmentPreparedEvent:SpringBoot对应Enviroment已经准备完毕,但此时上下文context还没有创建时触发的事件;
C. ApplicationContextInitializedEvent:上下文初始化执行的事件;
D. ApplicationPreparedEvent:SpringBoot上下文context创建完成,但此时spring中的bean是没有完全加载完成时触发的事件;
E. ApplicationStartedEvent:bean实例化完成,但是未调用Runners接口时触发的事件;
F. ApplicationReadyEvent:调用Runner 接口完毕时触发的事件;
G. ApplicationFailedEvent:SpringBoot启动异常失败时执行的事件 。
4. 举例
package com.ruhuanxingyun; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.nsac.business.listener.ApplicationStartup; @SpringBootApplication public class SpApp { public static void main(String[] args) { SpringApplication springApplication = new SpringApplication(SpApp.class); springApplication.addListeners(new ApplicationStartup()); springApplication.run(args); } }
package com.nsac.ruhuanxingyun; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; public class ApplicationStartup implements ApplicationListener<ContextRefreshedEvent> {
@Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext ac = event.getApplicationContext(); StepExecutor StepExecutor = new StepExecutor(ac.getEnvironment().getProperty("project-id"), ac.getBean("businessSingleJedisPool",redis.clients.jedis.JedisPool.class),
ac.getBean("redisCluster", redis.clients.jedis.JedisCluster.class)); Thread thread = new Thread(StepExecutor); thread.start(); } }
5. 自定义监听器
二、过滤器(Filter)
1. 使用场景:过滤器是处于客户端和服务器资源文件之间的一道过滤网,帮助我们过滤掉一些不符合要求的请求,通常用作Session校验和用户权限校验等;
2. 自定义Filter实现步骤
A. 实现javax.servlet.Filter类,重写三个方法;
B. init方法:在容器中创建当前过滤器的时候自动调用;
C. destory方法:在容器中销毁当前过滤器的时候自动调用;
D. doFilter方法:过滤的具体操作。
3. 组件扫描注册实现过滤器
A. 采用@WebFilter + @ServletComponentScan注解实现;
B. 代码
package com.ruhuanxingyun.web.manage.filter; import cn.hutool.core.util.StrUtil; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @description: 跨域 过滤器 * @author: ruphie * @date: Create in 2020/12/26 14:14 * @company: ruhuanxingyun */ @WebFilter(filterName = "corsFilter", urlPatterns = {"/api/*", "/gateway/*"}) public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; // 跨域时会发送option请求 if (!StrUtil.equals(HttpMethod.OPTIONS.name(), httpServletRequest.getMethod())) { chain.doFilter(request, response); return; } HttpServletResponse httpServletResponse = (HttpServletResponse) response; httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, OPTIONS, PUT, DELETE"); // 浏览器低版本不支持* httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "Authorization, Content-Type"); httpServletResponse.setStatus(HttpStatus.OK.value()); } }
C. 缺点是:多个过滤器指定执行顺序只能靠类名来达到排序效果,注意使用@Order注解失效。
4. SpringBoot FilterRegistrationBean注册实现过滤器
A. 采用@Configuration + @Bean注解实现;
B. 代码
5. AntPathMatcher匹配规则
A. ? 匹配一个字符,* 匹配0个或多个字符,** 匹配url中的0个或多个子目录;
三、拦截器(Interceptor)
1. 使用场景:拦截器是动态拦截action调用的对象,然后提供在action执行前后增加一些操作,功能与过滤器类似,但是标准和实现方式不同,通常用在登录认证、记录系统日志和通用处理等;
2. 自定义Interceptor实现步骤
A. 实现HandlerInterceptor类,重写三个方法;
B. preHandler方法:在Controller处理请求之前被调用,返回值是boolean类型,如果为true就继续下一步操作,若为false,则证明不符合拦截条件;
C. postHandler方法:在Controller处理请求执行完毕后,生成视图前执行;
D. afterCompletion方法:在DispatcherServlet完全处理请求后被调用,通常用于记录消耗时间,也可以对一些资源进行处理。
3. Filter与Interceptor的区别
A. Filter是JavaEE的标准,依赖于Servlet容器,生命周期也和容器一致,而Interceptor是SpringMVC中的内容,依赖于web框架;
B. Filter是基于回调函数实现的,无法注入Ioc容器中的bean,而Interceptor是基于反射实现的,可以注入Ioc容器中的bean;
C. Filter几乎可以对所有的请求起作用,而Interceptor只能对SpringMVC请求起作用;
D. 触发时机不同,Filter是在请求进入容器后且在进入servlet之前进行预处理,请求结束是在servlet处理完之后,Interceptor是在请求进入servlet后且进入controller之前进行预处理的,controller中渲染了对应的视图之后请求结束;
4. 拦截器实现
package com.ruhuanxingyun.web.config; import com.ruhuanxingyun.web.interceptor.OperateLogInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @description: 拦截器 配置 * @author: ruphie * @date: Create in 2021/1/6 16:52 * @company: ruhuanxingyun */ @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private OperateLogInterceptor operateLogInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(operateLogInterceptor) .addPathPatterns("/**"); } }
package com.ruhuanxingyun.web.interceptor; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map; /** * @description: 用户操作日志 拦截器 * @author: ruphie * @date: Create in 2021/1/6 16:43 * @company: ruhuanxingyun */ @Component public class OperateLogInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("49250"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("1232"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; Map map = (Map) httpServletRequest.getAttribute("response"); httpServletRequest.getRequestURI(); HttpServletResponse httpServletResponse = (HttpServletResponse) response; httpServletResponse.getOutputStream(); } }