SpringBoot注册Servlet、Filter、Listener、Interceptor四大组件

SpringBoot中注册四大组件

文章目录

  • SpringBoot中注册四大组件
  • 1. Servlet注册
    • 1. 基于配置类方式使用Servlet使用Servlet方式
    • 2. 基于纯注解方式配置Servlet
  • 2. Filter(过滤器)注册
    • 1. 以配置类方式注册Filter
    • 2. 以纯注解方式注册Filter
    • 3. 以注解的方式注册Filter执行顺序不生效问题
  • 3. Listener(监听器)注册
    • 1. `@Component`注解
    • 2. `@EventListener`注册监听
    • 3. 主启动配置监听
  • 4. Interceptor(拦截器)注册
  • 5. 执行顺序

SpringBoot版本:2.2.5 GA 版

GA=General Availability,字面意思是 一般或正常可用性。

代表的是官方正式发布的版本,推荐可广泛使用的版本,国外有的软件用GA来表示RELEASE版本。 RELEASE表示正式发布版

<parent>
     <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-parentartifactId>
        <version>2.2.5.RELEASEversion>
        <relativePath/> 
   parent>

1. Servlet注册

有两种使用方式

1.基于配置类方式使用Servlet

2.基于纯注解方式使用Servlet

1. 基于配置类方式使用Servlet使用Servlet方式

  1. 自定义一个MyServlet类,让其继承HttpServlet类

  2. 在配置类中使用ServletRegistrationBean类注册自定义MyServlet类

  3. 设置相关属性并访问

  1. MyServlet
package com.yuan.demo.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String requestURI = req.getRequestURI();
        System.out.println("requestURI" + requestURI);
        System.out.println("req.getRequestURL()" + req.getRequestURL());
        resp.getWriter().write("Hello,Servlet!!!");
    }
}

配置类

package com.yuan.demo.config;


import com.yuan.demo.filter.MyFilter;
import com.yuan.demo.listener.MyListener;
import com.yuan.demo.servlet.MyServlet;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/***
 * 注册自定义的Servlet
 */
@Configuration
public class RegisterServerConfig {

    /**
     * 注册自定义Servlet
     * @return
     */
    @Bean
    public ServletRegistrationBean myServlet(){
        ServletRegistrationBean<MyServlet> registrationBean = new ServletRegistrationBean<>(new MyServlet());
        registrationBean.addUrlMappings("/hello","/myServlet");
        return registrationBean;

    }

    /***
     * 注册自定义Filter
     * @return
     */
    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MyFilter());//设置自定义拦截器
        filterRegistrationBean.addUrlPatterns("/hello","/myServlet");//设置要拦截的请求
        return filterRegistrationBean;
    }

    /**
     * 注册自定义Listener
     * @return
     */
    @Bean
    public ServletListenerRegistrationBean myListener(){
        ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
        return registrationBean;
    }
}

2. 基于纯注解方式配置Servlet

  1. 写一个继承HttpServlet的类,并在其上面加上**@WebServlet**注解
  2. 在SpringBoot的主启动类上加上**@ServletComponentScan**注解
  1. MyServletOne.java
package com.yuan.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(value = {"/aa","/bb"}) //配置请求路径,其他参数看源码
public class MyServletOne extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("req.getRequestURI()====>"+req.getRequestURI());
        resp.getWriter().write("Hello,MyServletOne!!!");
    }
}
  1. SpringBoot主启动如下:
package com.yuan;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
public class MyServletApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyServletApplication.class,args);
    }
}
  1. 打开浏览器输入http://localhost:8080/aa,输出结果如下:
Hello,MyServletOne!!!

2. Filter(过滤器)注册

1. 以配置类方式注册Filter

  1. 自定义一个Filter类(如:MyFilter.java)让其实现Filter接口并实现相关方法
  2. 在配置类中注册 FilterRegistrationBean,设置过滤的URL等
  3. 编写测试案例进行过滤器测试

2. 以纯注解方式注册Filter

  1. 在在定义的Filter类中加入**@WebFilter**注解,并设置filterName及过滤的URL
  2. 在主启动类上加入 @ServletComponentScan注解
  3. 启动服务器进行测试

3. 以注解的方式注册Filter执行顺序不生效问题

  1. 问题描述,使用**@WebFilter方式注入filter后,用@Order**注解指定filter的执行顺序则不起作用

  2. 原因分析:

阅读源码发现:重点在ServletComponentHandler 处理带有注解WebFilter的类;handle方法中处理的attributes是@WebFilter的属性,因为@WebFilter本身是没有Order属性,所以构建的Filter将是默认的Order值,而上面源码可得知,类名可决定注册Filter的顺序(即Filter过滤顺序,因为此处只能注册默认的Order值)

  1. 解决方法:
    1. 以自定义的Filter名称(属性filterName=“myFilter”)来改变其执行顺序
    1. 使用配置类的方式,直接 对象.setOrder(2)来改变其顺序,order值越小优先级越高
//根据MyFilter会在MyFilterOne执行后再执行
@WebFilter(filterName = "bmyFilter",urlPatterns = {"/*","/one/*"})
public class MyFilter implements Filter {
    .......
}
//MyFilterOne会被先执行
@WebFilter(filterName = "amyFilter",urlPatterns = {"/*","/one/*"})
public class MyFilterOne implements Filter {...}

注:SpringBoot自带初始化的Filter

Spring Boot 自带的4中Filter,主要为了了解其过滤顺序,且与自定义Filter的执行顺序。(由Order值从小到大的顺序),由Filter类名来实现自定义Filter顺序,因Order为默认值,所以自带的4种Filter都会比自定义的Filter先执行。

 org.springframework.boot.web.servlet.FilterRegistrationBean 258 - Mapping filter: 'characterEncodingFilter' to: [/*]
 
 org.springframework.boot.web.servlet.FilterRegistrationBean 258 - Mapping filter: 'hiddenHttpMethodFilter' to: [/*]

org.springframework.boot.web.servlet.FilterRegistrationBean 258 - Mapping filter: 'httpPutFormContentFilter' to: [/*]

org.springframework.boot.web.servlet.FilterRegistrationBean 258 - Mapping filter: 'requestContextFilter' to: [/*]


  • CharacterEncodingFilter :编码过滤器
/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.web.servlet.filter;

import org.springframework.core.Ordered;
import org.springframework.web.filter.CharacterEncodingFilter;

/**
 * {@link CharacterEncodingFilter} that also implements {@link Ordered}.
 *
 * @author Phillip Webb
 * @since 2.0.0
 */
public class OrderedCharacterEncodingFilter extends CharacterEncodingFilter implements OrderedFilter {

	private int order = Ordered.HIGHEST_PRECEDENCE; //HIGHEST_PRECEDENCE = -2147483648;

	@Override
	public int getOrder() {
		return this.order;
	}

	/**
	 * Set the order for this filter.
	 * @param order the order to set
	 */
	public void setOrder(int order) {
		this.order = order;
	}
}

  • HiddenHttpMethodFilter :处理隐藏的PUT,DELETE等请求方法
/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.web.reactive.filter;

import org.springframework.core.Ordered;
import org.springframework.web.filter.reactive.HiddenHttpMethodFilter;

/**
 * {@link HiddenHttpMethodFilter} that also implements {@link Ordered}.
 *
 * @author Artsiom Yudovin
 * @since 2.0.5
 */
public class OrderedHiddenHttpMethodFilter extends HiddenHttpMethodFilter implements OrderedWebFilter {

	/**
	 * The default order is high to ensure the filter is applied before Spring Security.
	 */
	public static final int DEFAULT_ORDER = REQUEST_WRAPPER_FILTER_MAX_ORDER - 10000;

	private int order = DEFAULT_ORDER;

	@Override
	public int getOrder() {
		return this.order;
	}

	/**
	 * Set the order for this filter.
	 * @param order the order to set
	 */
	public void setOrder(int order) {
		this.order = order;
	}

}

  • HttpPutFormContentFilter :处理PUT表单请求
/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.filter;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

/**
 * {@link javax.servlet.Filter} that makes form encoded data available through
 * the {@code ServletRequest.getParameter*()} family of methods during HTTP PUT
 * or PATCH requests.
 *
 * 

The Servlet spec requires form data to be available for HTTP POST but * not for HTTP PUT or PATCH requests. This filter intercepts HTTP PUT and PATCH * requests where content type is {@code 'application/x-www-form-urlencoded'}, * reads form encoded content from the body of the request, and wraps the ServletRequest * in order to make the form data available as request parameters just like * it is for HTTP POST requests. * * @author Rossen Stoyanchev * @since 3.1 * @deprecated as of 5.1 in favor of {@link FormContentFilter} which is the same * but also handles DELETE. */ @Deprecated public class HttpPutFormContentFilter extends OncePerRequestFilter { private FormHttpMessageConverter formConverter = new AllEncompassingFormHttpMessageConverter(); /** * Set the converter to use for parsing form content. *

By default this is an instance of {@link AllEncompassingFormHttpMessageConverter}. */ public void setFormConverter(FormHttpMessageConverter converter) { Assert.notNull(converter, "FormHttpMessageConverter is required."); this.formConverter = converter; } public FormHttpMessageConverter getFormConverter() { return this.formConverter; } /** * The default character set to use for reading form data. * This is a shortcut for:
* {@code getFormConverter.setCharset(charset)}. */
public void setCharset(Charset charset) { this.formConverter.setCharset(charset); } @Override protected void doFilterInternal(final HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (("PUT".equals(request.getMethod()) || "PATCH".equals(request.getMethod())) && isFormContentType(request)) { HttpInputMessage inputMessage = new ServletServerHttpRequest(request) { @Override public InputStream getBody() throws IOException { return request.getInputStream(); } }; MultiValueMap<String, String> formParameters = this.formConverter.read(null, inputMessage); if (!formParameters.isEmpty()) { HttpServletRequest wrapper = new HttpPutFormContentRequestWrapper(request, formParameters); filterChain.doFilter(wrapper, response); return; } } filterChain.doFilter(request, response); } private boolean isFormContentType(HttpServletRequest request) { String contentType = request.getContentType(); if (contentType != null) { try { MediaType mediaType = MediaType.parseMediaType(contentType); return (MediaType.APPLICATION_FORM_URLENCODED.includes(mediaType)); } catch (IllegalArgumentException ex) { return false; } } else { return false; } } private static class HttpPutFormContentRequestWrapper extends HttpServletRequestWrapper { private MultiValueMap<String, String> formParameters; public HttpPutFormContentRequestWrapper(HttpServletRequest request, MultiValueMap<String, String> parameters) { super(request); this.formParameters = parameters; } @Override @Nullable public String getParameter(String name) { String queryStringValue = super.getParameter(name); String formValue = this.formParameters.getFirst(name); return (queryStringValue != null ? queryStringValue : formValue); } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> result = new LinkedHashMap<>(); Enumeration<String> names = getParameterNames(); while (names.hasMoreElements()) { String name = names.nextElement(); result.put(name, getParameterValues(name)); } return result; } @Override public Enumeration<String> getParameterNames() { Set<String> names = new LinkedHashSet<>(); names.addAll(Collections.list(super.getParameterNames())); names.addAll(this.formParameters.keySet()); return Collections.enumeration(names); } @Override @Nullable public String[] getParameterValues(String name) { String[] parameterValues = super.getParameterValues(name); List<String> formParam = this.formParameters.get(name); if (formParam == null) { return parameterValues; } if (parameterValues == null || getQueryString() == null) { return StringUtils.toStringArray(formParam); } else { List<String> result = new ArrayList<>(parameterValues.length + formParam.size()); result.addAll(Arrays.asList(parameterValues)); result.addAll(formParam); return StringUtils.toStringArray(result); } } } }

  • RequestContextFilter :设置请求的上下文环境
/*
 * Copyright 2002-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * Servlet Filter that exposes the request to the current thread,
 * through both {@link org.springframework.context.i18n.LocaleContextHolder} and
 * {@link RequestContextHolder}. To be registered as filter in {@code web.xml}.
 *
 * 

Alternatively, Spring's {@link org.springframework.web.context.request.RequestContextListener} * and Spring's {@link org.springframework.web.servlet.DispatcherServlet} also expose * the same request context to the current thread. * *

This filter is mainly for use with third-party servlets, e.g. the JSF FacesServlet. * Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient. * * @author Juergen Hoeller * @author Rod Johnson * @author Rossen Stoyanchev * @since 2.0 * @see org.springframework.context.i18n.LocaleContextHolder * @see org.springframework.web.context.request.RequestContextHolder * @see org.springframework.web.context.request.RequestContextListener * @see org.springframework.web.servlet.DispatcherServlet */ public class RequestContextFilter extends OncePerRequestFilter { private boolean threadContextInheritable = false; /** * Set whether to expose the LocaleContext and RequestAttributes as inheritable * for child threads (using an {@link java.lang.InheritableThreadLocal}). *

Default is "false", to avoid side effects on spawned background threads. * Switch this to "true" to enable inheritance for custom child threads which * are spawned during request processing and only used for this request * (that is, ending after their initial task, without reuse of the thread). *

WARNING: Do not use inheritance for child threads if you are * accessing a thread pool which is configured to potentially add new threads * on demand (e.g. a JDK {@link java.util.concurrent.ThreadPoolExecutor}), * since this will expose the inherited context to such a pooled thread. */ public void setThreadContextInheritable(boolean threadContextInheritable) { this.threadContextInheritable = threadContextInheritable; } /** * Returns "false" so that the filter may set up the request context in each * asynchronously dispatched thread. */ @Override protected boolean shouldNotFilterAsyncDispatch() { return false; } /** * Returns "false" so that the filter may set up the request context in an * error dispatch. */ @Override protected boolean shouldNotFilterErrorDispatch() { return false; } @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ServletRequestAttributes attributes = new ServletRequestAttributes(request, response); initContextHolders(request, attributes); try { filterChain.doFilter(request, response); } finally { resetContextHolders(); if (logger.isTraceEnabled()) { logger.trace("Cleared thread-bound request context: " + request); } attributes.requestCompleted(); } } private void initContextHolders(HttpServletRequest request, ServletRequestAttributes requestAttributes) { LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable); RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable); if (logger.isTraceEnabled()) { logger.trace("Bound request context to thread: " + request); } } private void resetContextHolders() { LocaleContextHolder.resetLocaleContext(); RequestContextHolder.resetRequestAttributes(); } }

3. Listener(监听器)注册

1. @Component注解

  1. 编写自定义监听类如RegListenerTwo实现ApplicationListener接口
  2. 在自定义监听类上面标注 @Component注解
package com.yuan.regcomponent;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class RegListenerTwo implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("RegListenerTwo====执行了");
    }
}

2. @EventListener注册监听

  1. 编写自定义监听类如RegListenerTwo实现ApplicationListener接口
  2. 在自定义监听类上面标注 @Component注解
  3. 在自定义类中编写一个监听方法,并在方法上标注@EventListener注解
package com.yuan.regcomponent;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class RegListenerThree {
    @EventListener
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("RegListenerThree====执行了");
    }
}

3. 主启动配置监听

  1. 编写自定义监听类如RegListenerOne实现ApplicationListener接口
  2. 在主启动类上面标注@ServletComponentScan
  3. 将自定义的监听类加入到SpringApplication的监听中
  1. 编写监听类
package com.yuan.regcomponent;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class RegListenerOne implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("RegListenerOne====执行了");
    }
}

  1. 直接启动类开启注解并添加自定义监听
package com.yuan;

import com.yuan.regcomponent.RegListenerOne;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan
public class YuanBootDiskfileApplication {

    public static void main(String[] args) {
        //SpringApplication.run(YuanBootDiskfileApplication.class, args);
        SpringApplication springApplication = new SpringApplication(YuanBootDiskfileApplication.class);
        springApplication.addListeners(new RegListenerOne());//添加自定义监听类
        springApplication.run(args);
    }

}

4. Interceptor(拦截器)注册

  1. 自定义拦截器
package com.yuan.demo.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义拦截器
 */
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor拦截器。。。。处理前");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        StringBuffer requestURL = request.getRequestURL();
        System.out.println("MyInterceptor拦截器拦截了请求:"+requestURL);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor拦截器。。。。处理后");
    }
}

  1. 注册拦截器
package com.yuan.demo.config;

import com.yuan.demo.interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration interceptor = registry.addInterceptor(new MyInterceptor());
        interceptor.addPathPatterns("/hello","/test");//拦截的url
        interceptor.excludePathPatterns("/login");//排除拦截的url
        interceptor.order(1);//拦截顺序
    }
}

5. 执行顺序

注意: 监听器 、 过滤器、 拦截器 执行优先顺序如下

监听器 > 过滤器 > 拦截器

  1. 同时配置了Servlet,过滤器,拦截器,优先顺序如下

Servlet>Filter>Interceptor

你可能感兴趣的:(spring,boot,servlet,java)