- 過濾器(Filter)
依賴于servlet容器。在實現(xiàn)上基于函數(shù)回調(diào),可以對幾乎所有請求進行過濾,但是缺點是一個過濾器實例只能在容器初始化時調(diào)用一次。使用過濾器的目的是用來做一些過濾操作,獲取我們想要獲取的數(shù)據(jù),比如:在過濾器中修改字符編碼;在過濾器中修改HttpServletRequest的一些參數(shù),包括:過濾低俗文字、危險字符等
@Slf4j
//@Component
public class TimeFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("time filter init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("filter start");
long startTime = new Date().getTime();
filterChain.doFilter(servletRequest, servletResponse);
log.info("consumingTime:{}",new Date().getTime()-startTime);
log.info("filter end");
}
@Override
public void destroy() {
log.info("time filter destroy");
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer{
@Bean
public FilterRegistrationBean timeFilter() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new TimeFilter());
ArrayList<String> urls = new ArrayList<>();
urls.add("/*");
registrationBean.setUrlPatterns(urls);
return registrationBean;
}
}
- 過濾器生命周期
- Filter的創(chuàng)建和銷毀由web服務(wù)器負(fù)責(zé)。 web應(yīng)用程序啟動時,web服務(wù)器將創(chuàng)建Filter的實例對象,并調(diào)用其init方法,完成對象的初始化功能,從而為后續(xù)的用戶請求作好攔截的準(zhǔn)備工作,filter對象只會創(chuàng)建一次,init方法也只會執(zhí)行一次。通過init方法的參數(shù),可獲得代表當(dāng)前filter配置信息的FilterConfig對象。
- web容器調(diào)用destroy方法銷毀Filter。destroy方法在Filter的生命周期中僅執(zhí)行一次。在destroy方法中,可以釋放過濾器使用的資源。
- 攔截器(Interceptor)
攔截器是AOP實現(xiàn)的一種策略,在AOP中用于在訪問某個方法或字段之前,進行攔截,在執(zhí)行之前或之后加入某些處理。
SpringMVC 中的Interceptor 攔截請求是通過HandlerInterceptor 來實現(xiàn)的。在SpringMVC 中定義一個Interceptor 非常簡單,主要有兩種方式,第一種方式是要定義的Interceptor類要實現(xiàn)了Spring 的HandlerInterceptor 接口,或者是這個類繼承實現(xiàn)了HandlerInterceptor 接口的類,比如Spring 已經(jīng)提供的實現(xiàn)了HandlerInterceptor 接口的抽象類HandlerInterceptorAdapter ;第二種方式是實現(xiàn)Spring的WebRequestInterceptor接口,或者是繼承實現(xiàn)了WebRequestInterceptor的類。
@Slf4j
@Component
public class TimeInterceptor implements HandlerInterceptor {
//在handler執(zhí)行之前,返回 boolean 值,true 表示繼續(xù)執(zhí)行,false 為停止執(zhí)行并返回
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("preHandle");
//攔截器可以拿到請求轉(zhuǎn)向的具體類和方法
log.info(((HandlerMethod) handler).getBean().getClass().getName());
log.info(((HandlerMethod) handler).getMethod().getName());
request.setAttribute("startTime", new Date().getTime());
return true;
}
//在handler執(zhí)行之后, 可以在返回之前對返回的結(jié)果進行修改
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle consumingTime:{}", new Date().getTime() - (long) request.getAttribute("startTime"));
}
//進行資源清理工作
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion consumingTime:{},ex:{}", new Date().getTime() - (long) request.getAttribute("startTime"), ex);
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer{
@Autowired
private TimeInterceptor timeInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeInterceptor);
}
}
- 兩者比較
- filter基于函數(shù)回調(diào),interceptor基于java反射機制;
- filter依賴于servlet容器; 攔截器是一個Spring的組件,歸Spring管理,配置 在Spring文件中,因此能使用Spring里的任何資源、對象,例如 Service對象、數(shù)據(jù)源、事務(wù)管理等,通過IoC注入到攔截器即可。
- filter對所有的請求進行過濾,interceptor只對action請求起作用。
- 在action的生命周期里,Interceptor可以被多次調(diào)用,而Filter只能在容器初始化時調(diào)用一次。
- 執(zhí)行順序:過濾前-攔截前-action執(zhí)行-攔截后-過濾后
-
切片(Aspect)
image.png
@Aspect
@Component
@Slf4j
public class TimeAspect {
@Around("execution(* com.dzg.web.controller.UserController.*(..))")
public Object handleControllerMethod(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("timeAspect start");
Object proceed = joinPoint.proceed();
//Aspect可以拿到請求中的攜帶的參數(shù)信息,這是攔截器無法做到的,但其無法拿到request和response
Object[] args = joinPoint.getArgs();
for(Object arg :args){
log.info("arg:{}",arg);
}
log.info("timeAspect end");
return proceed;
}
}
-
攔截順序
image.png

