- 過(guò)濾器(Filter)
依賴于servlet容器镐躲。在實(shí)現(xiàn)上基于函數(shù)回調(diào)吨述,可以對(duì)幾乎所有請(qǐng)求進(jìn)行過(guò)濾候学,但是缺點(diǎn)是一個(gè)過(guò)濾器實(shí)例只能在容器初始化時(shí)調(diào)用一次具伍。使用過(guò)濾器的目的是用來(lái)做一些過(guò)濾操作翅雏,獲取我們想要獲取的數(shù)據(jù),比如:在過(guò)濾器中修改字符編碼人芽;在過(guò)濾器中修改HttpServletRequest的一些參數(shù)望几,包括:過(guò)濾低俗文字、危險(xiǎn)字符等
@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;
}
}
- 過(guò)濾器生命周期
- Filter的創(chuàng)建和銷(xiāo)毀由web服務(wù)器負(fù)責(zé)萤厅。 web應(yīng)用程序啟動(dòng)時(shí)橄抹,web服務(wù)器將創(chuàng)建Filter的實(shí)例對(duì)象靴迫,并調(diào)用其init方法,完成對(duì)象的初始化功能楼誓,從而為后續(xù)的用戶請(qǐng)求作好攔截的準(zhǔn)備工作矢劲,filter對(duì)象只會(huì)創(chuàng)建一次,init方法也只會(huì)執(zhí)行一次慌随。通過(guò)init方法的參數(shù)芬沉,可獲得代表當(dāng)前filter配置信息的FilterConfig對(duì)象。
- web容器調(diào)用destroy方法銷(xiāo)毀Filter阁猜。destroy方法在Filter的生命周期中僅執(zhí)行一次丸逸。在destroy方法中,可以釋放過(guò)濾器使用的資源剃袍。
- 攔截器(Interceptor)
攔截器是AOP實(shí)現(xiàn)的一種策略黄刚,在AOP中用于在訪問(wèn)某個(gè)方法或字段之前,進(jìn)行攔截民效,在執(zhí)行之前或之后加入某些處理憔维。
SpringMVC 中的Interceptor 攔截請(qǐng)求是通過(guò)HandlerInterceptor 來(lái)實(shí)現(xiàn)的。在SpringMVC 中定義一個(gè)Interceptor 非常簡(jiǎn)單畏邢,主要有兩種方式业扒,第一種方式是要定義的Interceptor類(lèi)要實(shí)現(xiàn)了Spring 的HandlerInterceptor 接口,或者是這個(gè)類(lèi)繼承實(shí)現(xiàn)了HandlerInterceptor 接口的類(lèi)舒萎,比如Spring 已經(jīng)提供的實(shí)現(xiàn)了HandlerInterceptor 接口的抽象類(lèi)HandlerInterceptorAdapter 程储;第二種方式是實(shí)現(xiàn)Spring的WebRequestInterceptor接口,或者是繼承實(shí)現(xiàn)了WebRequestInterceptor的類(lèi)臂寝。
@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");
//攔截器可以拿到請(qǐng)求轉(zhuǎn)向的具體類(lèi)和方法
log.info(((HandlerMethod) handler).getBean().getClass().getName());
log.info(((HandlerMethod) handler).getMethod().getName());
request.setAttribute("startTime", new Date().getTime());
return true;
}
//在handler執(zhí)行之后, 可以在返回之前對(duì)返回的結(jié)果進(jìn)行修改
@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"));
}
//進(jìn)行資源清理工作
@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反射機(jī)制;
- filter依賴于servlet容器掏缎; 攔截器是一個(gè)Spring的組件皱蹦,歸Spring管理,配置 在Spring文件中御毅,因此能使用Spring里的任何資源根欧、對(duì)象,例如 Service對(duì)象端蛆、數(shù)據(jù)源、事務(wù)管理等酥泛,通過(guò)IoC注入到攔截器即可今豆。
- filter對(duì)所有的請(qǐng)求進(jìn)行過(guò)濾嫌拣,interceptor只對(duì)action請(qǐng)求起作用。
- 在action的生命周期里呆躲,Interceptor可以被多次調(diào)用异逐,而Filter只能在容器初始化時(shí)調(diào)用一次。
- 執(zhí)行順序:過(guò)濾前-攔截前-action執(zhí)行-攔截后-過(guò)濾后
-
切片(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可以拿到請(qǐng)求中的攜帶的參數(shù)信息插掂,這是攔截器無(wú)法做到的灰瞻,但其無(wú)法拿到request和response
Object[] args = joinPoint.getArgs();
for(Object arg :args){
log.info("arg:{}",arg);
}
log.info("timeAspect end");
return proceed;
}
}
-
攔截順序
image.png