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

SpringBoot中注册四大组件

文章目录

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

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

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 = { "/testOne", "/testTwo" }) // 配置请求路径,其他参数看源码
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.springboot;

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. springboot应用启动

    2.打开浏览器输入http://localhost:8066/springbootDemo/testOne,输出结果如下:

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. 解决方法:
  • 以自定义的Filter名称(属性filterName=“myFilter”)来改变其执行顺序
  • 使用配置类的方式,直接 对象.setOrder(2)来改变其顺序,order值越小优先级越高

MyFilterOne:

package com.springboot;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

//根据MyFilter会在MyFilterOne执行后再执行
@WebFilter(filterName = "myFilterOne",urlPatterns = {"/*","/one/*"})
public class MyFilterOne implements Filter {

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("********myFilterOne*********");
	}

}

MyFilterTwo: 

package com.springboot;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

//MyFilterOne会被先执行
@WebFilter(filterName = "myFilterTwo",urlPatterns = {"/*","/one/*"})
public class MyFilterTwo implements Filter{

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("********myFilterTwo*********");
	}

}

注: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 :编码过滤器
package com.springboot;

import org.springframework.boot.web.servlet.filter.OrderedFilter;
import org.springframework.core.Ordered;
import org.springframework.web.filter.CharacterEncodingFilter;

public class OrderedCharacterEncodingFilter extends CharacterEncodingFilter implements OrderedFilter {

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

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

	
	public void setOrder(int order) {
		this.order = order;
	}
}

  • HiddenHttpMethodFilter :处理隐藏的PUT,DELETE等请求方法
package com.springboot;

import org.springframework.boot.web.reactive.filter.OrderedWebFilter;


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

public class OrderedHiddenHttpMethodFilter extends HiddenHttpMethodFilter implements OrderedWebFilter {

	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表单请求
package com.springboot;

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;
import org.springframework.web.filter.OncePerRequestFilter;

public class HttpPutFormContentFilter extends OncePerRequestFilter {

	private FormHttpMessageConverter formConverter = new AllEncompassingFormHttpMessageConverter();

	/**
	 * Set the converter to use for parsing form content.
	 * <p>
	 * 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:<br>
	 * {@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 :设置请求的上下文环境
package com.springboot;

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;
import org.springframework.web.filter.OncePerRequestFilter;

public class RequestContextFilter extends OncePerRequestFilter {

	private boolean threadContextInheritable = false;

	public void setThreadContextInheritable(boolean threadContextInheritable) {
		this.threadContextInheritable = threadContextInheritable;
	}

	@Override
	protected boolean shouldNotFilterAsyncDispatch() {
		return false;
	}

	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.springboot;


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.springboot;

import org.springframework.context.ApplicationEvent;
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.springboot;

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.springboot;

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

@SpringBootApplication
@ServletComponentScan
public class MyBootDiskfileApplication {

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

}

4. Interceptor(拦截器)注册

  1. 自定义拦截器
package com.springboot;

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

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

/**
 * 自定义拦截器
 */
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.springboot;

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

  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值