Actual Spring Boot 2.0 Series (5) — прослушиватель, сервлет, фильтр и перехватчик

Spring Boot Java задняя часть Микросервисы Архитектура сервер Spring исходный код gradle

предисловие

Аутентификация и авторизация пользователей, ведение журналаMDC,кодировать декодировать,UAПроверка, многотерминальная переписка и т. д. должны пройтизапрос на перехватдля обработки. тогда нужноServlet,Filter,Listener,Interceptorэти компоненты. вместоSpring Bootпроект преобразован вSpring BootВ проекте необходимо использовать предыдущие коды, поэтому необходимо понимать их и ихиспользованиеижизненный цикл.

Статьи из этой серии

  1. Actual Spring Boot 2.0 Series (1) — Создание образов Docker с помощью Gradle
  2. Actual Spring Boot 2.0 Series (2) — глобальная обработка исключений и тестирование
  3. Actual Spring Boot 2.0 Series (3) — Подробное объяснение асинхронных вызовов с использованием @Async
  4. Actual Spring Boot 2.0 Series (4) — Использование WebAsyncTask для обработки асинхронных задач
  5. Actual Spring Boot 2.0 Series (5) — прослушиватель, сервлет, фильтр и перехватчик
  6. Actual Spring Boot 2.0 Series (6) — несколько реализаций одномашинных задач синхронизации

текст

1. Введение нескольких компонентов

1.1 Слушатель

Listenerможет контролироватьwebодин из серверовдействие события, и запустить зарегистрированныйПерезвони. простой языкapplication,session,requestтри объектасоздать/смертьилиДобавления, удаления и модификациисвойство, функциональный компонент, который автоматически выполняет код.

1.2. Servlet

Servletэто операцияСервис-терминализjavaприложение, сНезависимость от платформы и протоколафункции и могут быть динамически сгенерированыwebстраница, она работает назапрос клиентаиответ серверасредний слой.

1.3 Фильтр

FilterправильноЗапрос пользователяпровестипредварительная обработка, затем передайте запросServletпровестииметь дело сигенерировать ответ,НаконецFilterПравильно сноваответ серверапровестиПостобработка.Filterэто повторно используемый фрагмент кода, часто используемый для преобразованияHTTP просить,откликиинформация заголовка.Filterв отличиеServlet, он не может производитьотклик, но толькоИсправлятьдля ресурсапроситьилиотклик.

1.4. Перехватчик

похожийАспектно-ориентированное программированиесерединаразделиУведомление, мы проходимДинамический проксик одномуservice()способ добавитьУведомлениеСделайте функциональные улучшения. Например, перед выполнением методапроцесс инициализации, после выполнения методаПостобработка.перехватчикмысль иAOPпохоже, разница естьперехватчиктолько правильноControllerизHTTPзапрос на перехват.

2. Фильтры против перехватчиков

2.1 Разница между ними

  1. Filterоснован наобратный вызов функции, покаInterceptorоснован наJava отражениеиДинамический прокси.

  2. Filterзависит отServletконтейнер, покаInterceptorЭто не зависит отServletконтейнер.

  3. Filterпочтивсе запросыработает, покаInterceptorтолько правильноControllerработает по запросу.

2.2 Порядок исполнения

на заказServletДля процесса распределения запросов:

  1. Filterобработка запроса фильтра;
  2. Servletобработка запросов;
  3. FilterОбработка ответа фильтра.

на заказControllerПроцесс распределения запросов для:

  1. Filterобработка запроса фильтра;
  2. Interceptorобработка запроса на перехват;
  3. соответствующийHandlerAdapterобработка запросов;
  4. InterceptorОбработка ответа на перехват;
  5. Interceptorокончательная обработка;
  6. FilterОбработка ответа фильтра.

3. Подготовка окружающей среды

Настройка зависимостей градиента

использоватьSpring InitializerСоздаватьgradleпроектspring-boot-listener-servlet-filter-interceptor, добавляйте связанные зависимости при создании. получить начальныйbuild.gradleследующее:

buildscript {
    ext {
        springBootVersion = '2.0.3.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'io.ostenant.springboot.sample'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}


dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

Настроить класс входа при запуске

настроитьSpring BootЗапустите начальный класс, здесь вам нужно настроить две аннотации.

  • @ServletComponentScan: разрешитьSpring Bootсканировать и монтировать текущийпуть к пакетуиподпутьнастроен подServlet.

  • @EnableWvc: разрешитьSpring BootнастроитьSpring MVCСвязанные пользовательские свойства, такие как: перехватчики, обработчики ресурсов, преобразователи сообщений и т. д.

@EnableWebMvc
@ServletComponentScan
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4. Настройте прослушиватель Listener

настроитьServletContextСлушатель, используй@WebListenerОтметьте это. существуетServletконтейнеринициализацияв процессе,contextInitialized()метод будет вызываться в контейнереразрушатьбудет вызван, когдаcontextDestroyed().

@WebListener
public class IndexServletContextListener implements ServletContextListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(IndexServletContextListener.class);
    public static final String INITIAL_CONTENT = "Content created in servlet Context";

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        LOGGER.info("Start to initialize servlet context");
        ServletContext servletContext = sce.getServletContext();
        servletContext.setAttribute("content", INITIAL_CONTENT);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        LOGGER.info("Destroy servlet context");
    }
}

Здесь, когда контейнер инициализирован, перейдите кServletContextКонтекст устанавливает имя параметра вINITIAL_CONTENT, к которым можно получить прямой глобальный доступ.

5. Настройте сервлет

настроитьIndexHttpServlet, переписатьHttpServletизdoGet()метод, прямой выводIndexHttpServletОпределенныйПараметры инициализацииИ вIndexServletContextListenerнаборServletContextпараметр контекста.

@WebServlet(name = "IndexHttpServlet",
        displayName = "indexHttpServlet",
        urlPatterns = {"/index/IndexHttpServlet"},
        initParams = {
                @WebInitParam(name = "createdBy", value = "Icarus"),
                @WebInitParam(name = "createdOn", value = "2018-06-20")
        }
)
public class IndexHttpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        resp.getWriter().println(format("Created by %s", getInitParameter("createdBy")));
        resp.getWriter().println(format("Created on %s", getInitParameter("createdOn")));
        resp.getWriter().println(format("Servlet context param: %s",
                req.getServletContext().getAttribute("content")));
    }
}

настроить@WebServletАннотация используется для регистрации этогоServlet,@WebServletаннотированныйкаждый параметрсоответствуют соответственноweb.xmlКонфигурация в:

<servlet-mapping>  
    <servlet-name>IndexHttpServlet</servlet-name>
    <url-pattern>/index/IndexHttpServlet</url-pattern>
</servlet-mapping>
<servlet>  
    <servlet-name>IndexHttpServlet</servlet-name>  
    <servlet-class>io.ostenant.springboot.sample.servlet.IndexHttpServlet</servlet-class>
    <init-param>
        <param-name>createdBy</param-name>
        <param-value>Icarus</param-value>
    </init-param>
    <init-param>
        <param-name>createdOn</param-name>
        <param-value>2018-06-20</param-value>
    </init-param>
</servlet>  

6. Настройте фильтр Фильтр

ОдинServletЗапросы могут быть сделаны через несколькоFilterотфильтровать и, наконец,ServletОбработка и ответ клиенту. Вот пример настройки двух фильтров:

FirstIndexFilter.java

@WebFilter(filterName = "firstIndexFilter",
        displayName = "firstIndexFilter",
        urlPatterns = {"/index/*"},
        initParams = @WebInitParam(
                name = "firstIndexFilterInitParam",
                value = "io.ostenant.springboot.sample.filter.FirstIndexFilter")
)
public class FirstIndexFilter implements Filter {
    private static final Logger LOGGER = LoggerFactory.getLogger(FirstIndexFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("Register a new filter {}", filterConfig.getFilterName());
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        LOGGER.info("FirstIndexFilter pre filter the request");
        String filter = request.getParameter("filter1");
        if (isEmpty(filter)) {
            response.getWriter().println("Filtered by firstIndexFilter, " +
                    "please set request parameter \"filter1\"");
            return;
        }
        chain.doFilter(request, response);
        LOGGER.info("FirstIndexFilter post filter the response");
    }

    @Override
    public void destroy() {
        LOGGER.info("Destroy filter {}", getClass().getName());
    }
}

выше@WebFilterсвязанные свойства конфигурации, соответствующиеweb.xmlКонфигурация выглядит следующим образом:

<filter-mapping>
    <filter-name>firstIndexFilter</filter-name>
    <filter-class>io.ostenant.springboot.sample.filter.FirstIndexFilter</filter-class>
    <url-pattern>/index/*</url-pattern>
    <init-param>
        <param-name>firstIndexFilterInitParam</param-name>
        <param-value>io.ostenant.springboot.sample.filter.FirstIndexFilter</param-value>
    </init-param>
</filter-mapping>

настроитьFirstIndexFilter,использовать@WebFilterАннотации отмечены. когдаFirstIndexFilterВо время инициализации он будет выполнятьinit()метод. Каждый путь запроса соответствуетurlPatternsКогда вы настроите путь, вы войдетеdoFilter()метод, чтобы быть конкретнымпроситьиФильтрация ответов.

когдаHTTPзапросить переносfilter1параметр, запрос будет снят, в противном случае напрямуюпрерывание фильтра, чтобы завершить обработку запроса.

SecondIndexFilter.java

@WebFilter(filterName = "secondIndexFilter",
        displayName = "secondIndexFilter",
        urlPatterns = {"/index/*"},
        initParams = @WebInitParam(
                name = "secondIndexFilterInitParam",
                value = "io.ostenant.springboot.sample.filter.SecondIndexFilter")
)
public class SecondIndexFilter implements Filter {
    private static final Logger LOGGER = LoggerFactory.getLogger(SecondIndexFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("Register a new filter {}", filterConfig.getFilterName());
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        LOGGER.info("SecondIndexFilter pre filter the request");
        String filter = request.getParameter("filter2");
        if (isEmpty(filter)) {
            response.getWriter().println("Filtered by firstIndexFilter, " +
                    "please set request parameter \"filter2\"");
            return;
        }
        chain.doFilter(request, response);
        LOGGER.info("SecondIndexFilter post filter the response");

    }

    @Override
    public void destroy() {
        LOGGER.info("Destroy filter {}", getClass().getName());
    }
}

выше@WebFilterсвязанные свойства конфигурации, соответствующиеweb.xmlКонфигурация выглядит следующим образом:

<filter-mapping>
    <filter-name>secondIndexFilter</filter-name>
    <filter-class>io.ostenant.springboot.sample.filter.SecondIndexFilter</filter-class>
    <url-pattern>/index/*</url-pattern>
    <init-param>
        <param-name>secondIndexFilterInitParam</param-name>
        <param-value>io.ostenant.springboot.sample.filter.SecondIndexFilter</param-value>
    </init-param>
</filter-mapping>

настроитьSecondIndexFilter,использовать@WebFilterАннотации отмечены. когдаSecondIndexFilterВо время инициализации он будет выполнятьinit()метод. Каждый путь запроса соответствуетurlPatternsКогда вы настроите путь, вы войдетеdoFilter()метод, чтобы быть конкретнымпроситьиФильтрация ответов.

когдаHTTPзапросить переносfilter2параметр, запрос будет снят, в противном случае напрямуюпрерывание фильтра, чтобы завершить обработку запроса.

приди и посмотриdoFilter()Три основных параметра:

  • ServletRequest: не прибылServletизHTTPпросить;
  • Ответ сервлета: отServletобработано и сгенерированоHTTPотклик;
  • FilterChain: цепочка фильтровобъект, несколько могут быть зарегистрированы последовательнофильтр.
FilterChain.doFilter(request, response);

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

Конфигурация контроллера контроллера

настроитьIndexController, для тестирования/index/IndexControllerБудет ли путьFilterфильтр иInterceptorПерехватите и проверьте порядок этих двоих.

@RestController
@RequestMapping("index")
public class IndexController {
    @GetMapping("IndexController")
    public String index() throws Exception {
        return "IndexController";
    }
}

7. Настраиваем перехватчик Interceptor

перехватчикInterceptorтолько правильноHandlerэффективный.Spring MVCбыло быControllerкаждый изметод запросасоздан какHandlerобъект, поHandlerMappingОбъект направляет запросы к определеннымHandler, затем поHandlerAdapterзапрос через отражениеиметь дело сиотклик, с вкраплениямиОбработка перехвата.

написать перехватчик

Чтобы различать журналы, следующее то же самое, что иIndexControllerНастройте два класса перехватчиков:

FirstIndexInterceptor.java

public class FirstIndexInterceptor implements HandlerInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(FirstIndexInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LOGGER.info("FirstIndexInterceptor pre intercepted the request");
        String interceptor = request.getParameter("interceptor1");
        if (isEmpty(interceptor)) {
            response.getWriter().println("Filtered by FirstIndexFilter, " +
                    "please set request parameter \"interceptor1\"");
            return false;
        }
        return true;
    }

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

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        LOGGER.info("FirstIndexInterceptor do something after request completed");
    }
}

SecondIndexInterceptor.java

public class SecondIndexInterceptor implements HandlerInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(SecondIndexInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LOGGER.info("SecondIndexInterceptor pre intercepted the request");
        String interceptor = request.getParameter("interceptor2");
        if (isEmpty(interceptor)) {
            response.getWriter().println("Filtered by SecondIndexInterceptor, " +
                    "please set request parameter \"interceptor2\"");
            return false;
        }
        return true;
    }

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

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        LOGGER.info("SecondIndexInterceptor do something after request completed");
    }
}

Настроить перехватчик

существуетSpring BootсерединаНастроить перехватчикочень просто, просто реализуйтеWebMvcConfigurerинтерфейс, вaddInterceptors()через методInterceptorRegistryДобавить кперехватчикипуть совпаденияВот и все.

@Configuration
public class WebConfiguration implements WebMvcConfigurer {
    private static final Logger LOGGER = LoggerFactory.getLogger(WebConfiguration.class);

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new FirstIndexInterceptor()).addPathPatterns("/index/**");
        registry.addInterceptor(new SecondIndexInterceptor()).addPathPatterns("/index/**");
        LOGGER.info("Register FirstIndexInterceptor and SecondIndexInterceptor onto InterceptorRegistry");
    }
}

соответствующийSpring XMLКонфигурация выглядит следующим образом:

<bean id="firstIndexInterceptor"
class="io.ostenant.springboot.sample.interceptor.FirstIndexInterceptor"></bean>
<bean id="secondIndexInterceptor"
class="io.ostenant.springboot.sample.interceptor.SecondIndexInterceptor"></bean>

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/index/**" />
        <ref local="firstIndexInterceptor" />
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/index/**" />
        <ref local="secondIndexInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

Принципиальный анализ

мы достигаем путемHandlerInterceptorинтерфейс для разработкиперехватчик,приди и посмотриHandlerInterceptorТри важных метода интерфейса:

  • preHandle(): вcontrollerполучить запрос, обработатьrequestВыполнено ранее, возвращаемое значение равноboolean, возвращаемое значение равноtrueзатем выполнитьpostHandle()иafterCompletion()метод; если возвращаетсяfalseнопрерыватьвоплощать в жизнь.

  • postHandle (): вcontrollerПосле обработки запроса,ModelAndViewВыполняется перед обработкой, вы можетерезультат ответамодифицировать.

  • после завершения(): вDispatchServletОбработка этого запроса завершена, то есть генерацияModelAndViewВыполнить потом.

Просто взгляните нижеSpring MVCцентральный планировщикDispatcherServletизdoDispatch()Принципы метода, основное вниманиеперехватчикПорядок выполнения трех вышеуказанных методов.

  • doDispatch(): DispatchServletОсновной метод обработки отправки запроса.
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try {
        ModelAndView mv = null;
        Exception dispatchException = null;
        try {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);
            // Determine handler for the current request.
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }
            // Determine handler adapter for the current request.
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            // 1. 按从前往后的顺序调用各个拦截器preHandle()方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 2. HandlerAdapter开始真正的请求处理并生产响应视图对象
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);

            // 3. 按照从后往前的顺序依次调用各个拦截器的postHandle()方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        } catch (Exception ex) {
            dispatchException = ex;
        } catch (Throwable err) {
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    } catch (Exception ex) {
        // 4. 最终会调用拦截器的afterCompletion()方法
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    } catch (Throwable err) {
        // 4. 最终会调用拦截器的afterCompletion()方法
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else {
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

Несколько примечаний вышеHandlerExecutionChainМетоды:applyPreHandle(),applyPostHandle()иtriggerAfterCompletion().

  • applyPreHandle(): нажмитеСпереди назадПорядок вызова каждого перехватчикаpreHandle()метод. кто-нибудьHandlerInterceptorперехват возвратаfalse,ноpreHandle()возвращениеfalse, который записывает местоположение перехватчикаinterceptorIndex, затем прервите обработку перехвата и, наконец, вызовитеAfterCompletion()метод и возвратfalse.
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = 0; i < interceptors.length; i++) {
            HandlerInterceptor interceptor = interceptors[i];
            if (!interceptor.preHandle(request, response, this.handler)) {
                triggerAfterCompletion(request, response, null);
                return false;
            }
            this.interceptorIndex = i;
        }
    }
    return true;
}
  • applyPostHandle(): согласнозадом напередПорядок вызова каждого перехватчика по очередиpostHandle()метод. только если всеHandlerInterceptorизpreHandle()метод возвращаетtrueтолько когда появляется возможность выполнитьapplyPostHandle()метод.
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
        throws Exception {
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = interceptors.length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            interceptor.postHandle(request, response, this.handler, mv);
        }
    }
}
  • triggerAfterCompletion: triggerAfterCompletion()только вpreHandle()метод возвращаетfalseиПрограмма выдает исключениепри исполнении. существуетpreHandle()метод, черезinterceptorIndexзарегистрированный возвратfalseизИндекс перехватчика. однаждыapplyPreHandle()метод возвращаетfalse, затем вернуться из текущегоfalseперехватчикзадом напередисполнениеafterCompletion()метод.
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
        throws Exception {
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = this.interceptorIndex; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            try {
                interceptor.afterCompletion(request, response, this.handler, ex);
            }
            catch (Throwable ex2) {
                logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
            }
        }
    }
}

8. Запустите тест

тестирование жизненного цикла

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

  • регистрSpring MVCизdispatcherServletи обычайIndexHttpServlet.
2018-06-23 09:39:55.400  INFO 12301 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
2018-06-23 09:39:55.404  INFO 12301 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet IndexHttpServlet mapped to [/index/IndexHttpServlet]

Уведомление:dispatcherServletизload-up-onstartupза1, будет иметь приоритет над другимиServletзагрузить.

  • Расставь все фильтры по порядкуFilterОбъекты отображаются с путями, гдеcharacterEncodingFilterдаSpring MVCВстроенное решение для искаженных символовFilter.
2018-06-23 09:39:55.408  INFO 12301 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-06-23 09:39:55.409  INFO 12301 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'firstIndexFilter' to urls: [/index/*]
2018-06-23 09:39:55.409  INFO 12301 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'secondIndexFilter' to urls: [/index/*]
  • инициализацияIndexServletContextListenerи выполнитьcontextInitialized()метод инициализации контекста.
2018-06-23 09:39:55.429  INFO 12301 --- [ost-startStop-1] i.o.s.s.l.IndexServletContextListener    : Start to initialize servlet context
  • выполнять последовательноFilterизinit()метод для инициализации.
2018-06-23 09:39:55.432  INFO 12301 --- [ost-startStop-1] i.o.s.sample.filter.SecondIndexFilter     : Register a new filter secondIndexFilter
2018-06-23 09:39:55.434  INFO 12301 --- [ost-startStop-1] i.o.s.sample.filter.FirstIndexFilter      : Register a new filter firstIndexFilter
  • Создайте, инициализируйте перехватчик и зарегистрируйте его единообразно дляInterceptorRegistryначальство.
2018-06-23 09:39:55.502  INFO 13150 --- [           main] i.o.s.s.interceptor.WebConfiguration     : Register FirstIndexInterceptor and SecondIndexInterceptor onto InterceptorRegistry
  • правильноIndexControllerпроцесс,просить URIиПодходсопоставить сHandlerMappingвключено и кэшировано.
2018-06-23 09:39:55.541  INFO 12301 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/index/IndexController],methods=[GET]}" onto public java.lang.String io.ostenant.springboot.sample.controller.IndexController.index() throws java.lang.Exception

закрытиеSpring BootПри применении приложения наблюдайте за выходным журналом следующим образом:

2018-06-23 10:07:03.294  INFO 12301 --- [ost-startStop-2] i.o.s.sample.filter.FirstIndexFilter     : Destroy filter io.ostenant.springboot.sample.filter.SecondIndexFilter
2018-06-23 10:07:03.294  INFO 12301 --- [ost-startStop-2] i.o.s.sample.filter.FirstIndexFilter     : Destroy filter io.ostenant.springboot.sample.filter.FirstIndexFilter
2018-06-23 10:07:03.294  INFO 12301 --- [ost-startStop-2] i.o.s.s.l.IndexServletContextListener    : Destroy servlet context

Вы можете увидеть фильтр, настроенный вышеdestroy()Методы иIndexServletContextListenerизcontextDestroyed()Способы называются.

проверка контроля доступа

Тест сервлета

доступhttp://localhost:8080/index/IndexHttpServlet, содержимое страницы ответа выглядит следующим образом:

доступhttp://localhost:8080/index/IndexHttpServlet?filter1=filter1, содержимое страницы ответа выглядит следующим образом:

доступhttp://localhost:8080/index/IndexHttpServlet?filter1=filter1&filter2=filter2, содержимое страницы ответа выглядит следующим образом:

Просмотрите журнал вывода консоли, чтобы проверитьфильтрПорядок фильтров правильный.

2018-06-23 10:19:47.944  INFO 13150 --- [nio-8080-exec-1] i.o.s.sample.filter.FirstIndexFilter     : FirstIndexFilter pre filter the request
2018-06-23 10:19:47.944  INFO 13150 --- [nio-8080-exec-1] i.o.s.sample.filter.SecondIndexFilter    : SecondIndexFilter pre filter the request
2018-06-23 10:19:47.944  INFO 13150 --- [nio-8080-exec-1] i.o.s.sample.filter.SecondIndexFilter    : SecondIndexFilter post filter the response
2018-06-23 10:19:47.944  INFO 13150 --- [nio-8080-exec-1] i.o.s.sample.filter.FirstIndexFilter     : FirstIndexFilter post filter the response

в заключении:индивидуальныефильтрправильноIndexHttpServletэффективным, при этомнастроитьПерехватчик вступает в силу.

тест контроллера

доступhttp://localhost:8080/index/IndexController, содержимое страницы ответа выглядит следующим образом:

доступhttp://localhost:8080/index/IndexController?filter1=filter1, содержимое страницы ответа выглядит следующим образом:

доступhttp://localhost:8080/index/IndexController?filter1=filter1&filter2=filter2, содержимое страницы ответа выглядит следующим образом:

доступhttp://localhost:8080/index/IndexController?filter1=filter1&filter2=filter2&interceptor1=interceptor1, содержимое страницы ответа выглядит следующим образом:

доступhttp://localhost:8080/index/IndexController?filter1=filter1&filter2=filter2&interceptor1=interceptor1&interceptor2=interceptor2, содержимое страницы ответа выглядит следующим образом:

2018-06-23 10:21:42.533  INFO 13150 --- [nio-8080-exec-4] i.o.s.sample.filter.FirstIndexFilter     : FirstIndexFilter pre filter the request
2018-06-23 10:21:42.533  INFO 13150 --- [nio-8080-exec-4] i.o.s.sample.filter.SecondIndexFilter    : SecondIndexFilter pre filter the request
2018-06-23 10:21:42.534  INFO 13150 --- [nio-8080-exec-4] i.o.s.s.i.FirstIndexInterceptor          : FirstIndexInterceptor pre intercepted the request
2018-06-23 10:21:42.534  INFO 13150 --- [nio-8080-exec-4] i.o.s.s.i.SecondIndexInterceptor         : SecondIndexInterceptor pre intercepted the request
2018-06-23 10:21:42.535  INFO 13150 --- [nio-8080-exec-4] i.o.s.s.i.SecondIndexInterceptor         : SecondIndexInterceptor post intercepted the response
2018-06-23 10:21:42.535  INFO 13150 --- [nio-8080-exec-4] i.o.s.s.i.FirstIndexInterceptor          : FirstIndexInterceptor post intercepted the response
2018-06-23 10:21:42.535  INFO 13150 --- [nio-8080-exec-4] i.o.s.s.i.SecondIndexInterceptor         : SecondIndexInterceptor do something after request completed
2018-06-23 10:21:42.535  INFO 13150 --- [nio-8080-exec-4] i.o.s.s.i.FirstIndexInterceptor          : FirstIndexInterceptor do something after request completed
2018-06-23 10:21:42.535  INFO 13150 --- [nio-8080-exec-4] i.o.s.sample.filter.SecondIndexFilter    : SecondIndexFilter post filter the response
2018-06-23 10:21:42.535  INFO 13150 --- [nio-8080-exec-4] i.o.s.sample.filter.FirstIndexFilter     : FirstIndexFilter post filter the response

в заключении:индивидуальныефильтриперехватчикправильноконтроллер Controllerэффективный. ифильтрприоритет выше, чемперехватчик.

резюме

В этой статье подробноListener,Servlet,Filter,ControllerиInterceptorЖдатьWebФункции, методы, порядок, объем и жизненный цикл различных компонентов. Приведен подробный пример кода в сочетании сисходный кодПроанализировал процесс, объединилконтрольная работаВывод проверен. Долгая история, я надеюсь, что вы всеServletкомпоненты иSpring MVCБолее четкое понимание компонентов фреймворка.


Добро пожаловать в технический публичный аккаунт: Zero One Technology Stack

零壹技术栈

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