通常来说,用户通过浏览器发起Request进入服务器后侧处理顺序如下:
引用
Client -> Listener -> ServletContainer -> Filter -> Servlet -> Interceptor
具体可以看看这里: http://rensanning.iteye.com/blog/2355214
大部分框架采用一个servlet分发请求到不同controller去处理,只有极个别场景会定义多个servlet来处理比较特殊需求。而Filter、Listener、Interceptor按需求一般来说都会是多个。
(1)Servlet 2.5采用web.xml定义Servlet、Filter、Listener
<web-app ...> <servlet> <servlet-name>spring</servlet-name> <servlet-class>com.rensanning.springtest.HelloWorldServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <url-pattern>/*</url-pattern> </servlet-mapping> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>com.rensanning.springtest.TestServletContextListener</listener-class> </listener> </web-app>
(2)Servlet 3.0开始不再需要web.xml,可以通过注解或Java代码定义Servlet/Filter等。
1)注解定义
@WebServlet(name="HelloWorldServlet",urlPatterns={"/HelloWorld"}, initParams={@WebInitParam(name="name",value="rensanning")}) public class HelloWorldServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().print("Hello " + getInitParameter("name")); } }
@WebFilter(filterName="HelloWorldFilter", urlPatterns="/HelloWorld") public class HelloWorldFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
引用
Servlet规范不支持注解Filter的执行顺序,仍需在 web.xml 中定义,web.xml中定义的<filter-mapping>的顺序就是他们的执行顺序。
@WebFilter(filterName="filter1", urlPatterns="/url1/*")
public class Filter1 implements Filter {}
@WebFilter(filterName="filter2", urlPatterns="/url2/*")
public class Filter2 implements Filter {}
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern />
</filter-mapping>
<filter-mapping>
<filter-name>filter2</filter-name>
<url-pattern />
</filter-mapping>
@WebFilter(filterName="filter1", urlPatterns="/url1/*")
public class Filter1 implements Filter {}
@WebFilter(filterName="filter2", urlPatterns="/url2/*")
public class Filter2 implements Filter {}
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern />
</filter-mapping>
<filter-mapping>
<filter-name>filter2</filter-name>
<url-pattern />
</filter-mapping>
@WebListener public class TestServletContextListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent event) { } @Override public void contextInitialized(ServletContextEvent event) { } }
2)动态注册
public class WebInitializer implements WebApplicationInitializer { public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException { // Servlet ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherContext)); dispatcher.addMapping("/"); dispatcher.setLoadOnStartup(1); dispatcher.setInitParameter("defaultHtmlEscape", "true"); // Filter FilterRegistration.Dynamic filter = container.addFilter("encodingFilter", CharacterEncodingFilter.class); filter.addMappingForUrlPatterns(null, false, "/*"); filter.setInitParameter("encoding", "UTF-8"); filter.setInitParameter("forceEncoding", "true"); // Listener servletContext.addListener(TestServletContextListener.class); } }
(3)Spring Boot也采用无web.xml,以Filter为例,添加方法如下:
1)通过@Component让Spring扫描到即可处理拦截处理所有请求
@Component public class TestFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }
2)通过@Configuration + @Bean来管理未被扫描到的Filter
public class MultipleFilter1 implements Filter { } public class MultipleFilter2 implements Filter { } @Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Bean public Filter filter1() { return new MultipleFilter1(); } @Bean public Filter filter2() { return new MultipleFilter2(); } }
3)通过@Configuration + @Bean + FilterRegistrationBean更灵活的设置Filter
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Bean public FilterRegistrationBean filter1() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new MultipleFilter1()); bean.setOrder(2); return bean; } @Bean public FilterRegistrationBean filter2() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new MultipleFilter2()); bean.setOrder(1); return bean; } }
4)通过@ServletComponentScan自动扫描@WebServlet, @WebFilter, @WebListener
@SpringBootApplication @ServletComponentScan public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
SpringBoot默认已经为应用添加了以下Servlet/Filter
引用
o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
定义Interceptor
public class TraceLoggingInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { } } @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { // <mvc:interceptors> registry.addInterceptor(traceLoggingInterceptor()) .addPathPatterns("/**/*.do") .addPathPatterns("/**/*.json"); } }