Серия статей Springboot фильтр против перехватчика

Java задняя часть Spring контейнер

Оригинальный адрес блога:блог Пимайка

предисловие

При фактической разработке проекта раньше, хотя фильтры и перехватчики полезны, понимание все еще немного невежественно и не полностью понято, В этой статье будет тщательно проанализирована разница и связь между ними.

фильтр

Фильтр Фильтр, определенный в спецификации сервлета, поддерживается контейнером сервлета, а интерфейс определен вjavax.servletВ пакете он в основном выполняет предварительную обработку клиентского запроса (HttpServletRequest) и постобработку ответа сервера (HttpServletResponse). Код интерфейса выглядит следующим образом:

package javax.servlet;

import java.io.IOException;

public interface Filter {
    void init(FilterConfig var1) throws ServletException;

    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;

    void destroy();
}

Проанализируйте три вышеуказанных метода интерфейса:

  • init(FilterConfig): интерфейс инициализации, который вызывается при инициализации пользовательского фильтра, имеет ту же функцию, что и метод инициализации сервлета.
  • doFilter(ServletRequest,ServletResponse,FilterChain): этот метод будет вызываться при поступлении запроса каждого пользователя и перед сервисным методом сервлета (если мы разрабатываем проект сервлета), а FilterChain представляет текущую всю цепочку запросов, вызываяFilterChain.doFilterВы можете продолжать передавать запрос.Если вы хотите перехватить запрос, вы можете не вызывать FilterChain.doFilter, тогда запрос будет возвращен напрямую.Таким образом, фильтр — это шаблон проектирования цепочки ответственности.,существуетspring securityТак же много использования фильтров, есть цепочка фильтров.
  • destroy: этот метод вызывается при уничтожении объекта Filter.Обратите внимание, что после того, как веб-контейнер вызовет этот метод, контейнер снова вызовет метод doFilter.

Пользовательский фильтр

Пользовательский класс Filter в springboot выглядит следующим образом:

@Component
public class MyFilter implements Filter {
    private Logger logger = LoggerFactory.getLogger(MyFilter.class);
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        logger.info("doFilter");
        //对request,response进行预处理
        //TODO 进行业务逻辑
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        logger.info("filter destroy");
    }
}

Метод FilterRegistrationBean

предоставляется в спрингбутFilterRegistrationBeanметод, этот класс предоставляет метод setOrder, который может установить значение порядка для нескольких фильтров. код показывает, как показано ниже:

@Configuration
public class FilterConfig {
    /**
     * 配置一个Filter注册器
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean filterRegistrationBean1() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(filter1());
        registrationBean.setName("filter1");
        //设置顺序
        registrationBean.setOrder(10);
        return registrationBean;
    }
    @Bean
    public FilterRegistrationBean filterRegistrationBean2() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(filter2());
        registrationBean.setName("filter2");
        //设置顺序
        registrationBean.setOrder(3);
        return registrationBean;
    }
    @Bean
    public Filter filter1() {
        return new MyFilter();
    }

    @Bean
    public Filter filter2() {
        return new MyFilter2();
    }
}

перехватчик

Перехватчик — это концепция, предложенная Spring.Он действует как фильтр.Он может перехватывать запросы пользователей и обрабатывать их соответствующим образом.Он может осуществлять более тонкий контроль.

В SpringMVC DispatcherServlet захватывает каждый запрос. Прежде чем достичь соответствующего контроллера, запрос может быть обработан перехватчиком. После предварительной обработки в перехватчике запрос наконец достигает контроллера.

Интерфейс перехватчикаorg.springframework.web.servlet.HandlerInterceptorИнтерфейс, код интерфейса следующий:

public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

Интерпретация методов интерфейса:

  • метод предварительной обработки: Предварительно обработайте запрос, отправленный клиентом. Если метод возвращает true, продолжайте выполнять последующие операции. Если он возвращает false, выполните обработку запроса прерывания, и запрос не будет отправлен в контроллер.
  • метод postHandler: Выполняется после обработки запроса, то есть обрабатывается после вызова метода Controller, конечно, при условии, что предыдущийpreHandleметод возвращает истину. Конкретно,postHandlerМетод будет вызываться до того, как DispatcherServlet вернет и отобразит представление, а это значит, что мы можем обработать контроллер в этом методе.ModelAndViewобъект для работы
  • метод afterCompletion: Этот метод выполняется после завершения всего запроса, конечно, посылка все ещеpreHandleВозвращаемое значение метода истинно. Этот метод обычно используется для очистки ресурсов.

пользовательский перехватчик

public class MyInterceptor implements HandlerInterceptor {
    private Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("preHandle....");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("postHandle...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("afterCompletion...");
    }
}

Зарегистрируйте перехватчик и одновременно настройте правила перехватчика.

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(handlerInterceptor())
                //配置拦截规则
                .addPathPatterns("/**");
    }
    @Bean
    public HandlerInterceptor handlerInterceptor() {
        return new MyInterceptor();
    }
}

Несколько перехватчиков работают вместе

В springMVC мы можем реализовать несколько перехватчиков и зарегистрировать их по очереди следующим образом:

   public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(handlerInterceptor())
                .addPathPatterns("/**");
        registry.addInterceptor(handlerInterceptor2())
                .addPathPatterns("/**");
    }

Порядок перехватчиков также связан с порядком их регистрации, как минимумpreHandleМетод такой: На следующем рисунке показан порядок выполнения при совместной работе двух перехватчиков:

img

На фото выше изМООК

Журнал спула также выводит тот же порядок выполнения:

io-9999-exec-2] c.p.filter.interceptor.MyInterceptor     : preHandle....
2018-09-13 12:13:31.292  INFO 9736 --- [nio-9999-exec-2] c.p.filter.interceptor.MyInterceptor2    : preHandle2....
2018-09-13 12:13:31.388  INFO 9736 --- [nio-9999-exec-2] c.p.filter.controller.HelloController    : username:pjmike,password:123456
2018-09-13 12:13:31.418  INFO 9736 --- [nio-9999-exec-2] c.p.filter.interceptor.MyInterceptor2    : postHandle2...
2018-09-13 12:13:31.418  INFO 9736 --- [nio-9999-exec-2] c.p.filter.interceptor.MyInterceptor     : postHandle...
2018-09-13 12:13:31.418  INFO 9736 --- [nio-9999-exec-2] c.p.filter.interceptor.MyInterceptor2    : afterCompletion2...
2018-09-13 12:13:31.418  INFO 9736 --- [nio-9999-exec-2] c.p.filter.interceptor.MyInterceptor     : afterCompletion...

Разница между перехватчиком и фильтром

Из приведенного выше описания перехватчиков и фильтров они очень похожи и могут обрабатывать запросы от клиентов, отличия заключаются в следующем:

  • разная сфера
    • Фильтр зависит от контейнера сервлета и может использоваться только в контейнере сервлета, веб-среде.
    • Перехватчик зависит от контейнера Spring и может быть вызван в контейнере Spring, независимо от того, в какой среде Spring находится в это время.
  • мелкозернистая разница
    • Управление фильтром относительно грубое, и его можно обработать только тогда, когда приходит запрос, а запрос и ответ упакованы.
    • Перехватчики обеспечивают более детальное управление и могут быть вызваны до или после обработки запроса контроллером или после того, как визуализированное представление представлено пользователю.
  • Разные уровни сложности прерывания выполнения цепочки
    • Перехватчики могутpreHandleВерните false внутри метода для прерывания
    • Фильтры более сложны, требуют обработки объектов запроса и ответа, чтобы вызвать прерывания, требуют дополнительных действий, таких как перенаправление пользователя на страницу с ошибкой.

резюме

Подводя итог, можно сказать, что перехватчики имеют более тонкое управление, чем фильтры. Они зависят от контейнера Spring и могут запускаться до или после запроса. Фильтры в основном зависят от сервлетов. Что могут фильтры, в основном могут перехватчики.

Ссылки и благодарности