1. 程式人生 > >Spring 梳理 - filter、interceptor、aop實現與區別 -第一篇

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();
        }
    }

三個攔截器的比較如下,根據自己的業務功能需求選擇最合適的攔截器。