Spring 梳理 - filter、interceptor、aop實現與區別 -第一篇
前言
專案中我們經常需要對RESTful api進行攔截,主流實現方法有filter、interceptor、aop,先說一下他們各自的實現。
Filter
AnimalFilter實現javax.servlet.Filter,專案啟動時已初始化完成,可在控制檯看到列印的初始化日誌。
@Component
public class AnimalFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("animalFilter 初始化。。。");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
logger.info("animalFilter doFilter 。。。");
chain.doFilter(request,response);//過濾器將請求往下傳遞
}
@Override
public void destroy() {
logger.info("animalFilter 銷燬。。。");
}
}
如何呼叫不被component修飾的filter,將上文中的component註解去除,通過下文方式,讓註解生效並設定註解生效的url請求地址資訊。
@Configuration
public class AnimalWebConfig {
@Bean
public FilterRegistrationBean animalFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
AnimalFilter animalFilter = new AnimalFilter();
filterRegistrationBean.setFilter(animalFilter);
List<String> urlPattern = new ArrayList<>();
urlPattern.add("/animal/getAnimalById/*");
filterRegistrationBean.setUrlPatterns(urlPattern);
return filterRegistrationBean;
}
}
由於filter獲取的引數為ServletRequest request, ServletResponse response, FilterChain chain,無法知道是哪個類的那個方法呼叫,更無法知道呼叫時的引數。
Interceptor
首先編寫一個AnimalInterceptor實現HandlerInteceptor方法,實現相應的三個方法,preHandle執行方法前執行返回的結果決定是否往下執行,postHandle當方法返回值時執行,afterCompletion無論成功或失敗都將執行,前提是preHandler要返回true。
@Component
public class AnimalInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
String methodName = handlerMethod.getMethod().getName();
logger.info("AnimalInterceptor:preHandle:methodName:" + methodName);
logger.info("AnimalInterceptor:preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
logger.info("AnimalInterceptor:preHandle:methodName:" + handlerMethod.getMethod().getName());
logger.info("AnimalInterceptor:postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.info("AnimalInterceptor:afterCompletion");
}
}
將寫好的AnimalInterceptor注入到spring的interceptor註冊中心即可
@Component
public class InterceptorConfig extends WebMvcConfigurerAdapter{
@Autowired
AnimalInterceptor animalInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(animalInterceptor);
}
}
雖然interceptor可以知道呼叫的controller,呼叫的方法,但獲取不到呼叫方法的引數。
AOP
編寫AnimalAspect如下,可將傳遞的引數打印出來,aop攔截規則設定請檢視,https://blog.csdn.net/FU250/article/details/80219415
@Aspect
@Component
public class AnimalAspect {
private Logger logger = LoggerFactory.getLogger(getClass());
@Around("execution(* com.imooc.security.demo.web.controller..*.*(..))")
public Object handleAnimalController(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Arrays.stream(proceedingJoinPoint.getArgs()).forEach(arg -> {
logger.info("arg:"+arg);
});
logger.info("AnimalAspect");
return proceedingJoinPoint.proceed();
}
}
三個攔截器的比較如下,根據自己的業務功能需求選擇最合適的攔截器。