SpringBoot中注册四大组件
文章目录
2. 基于纯注解方式配置Servlet
- 写一个继承HttpServlet的类,并在其上面加上**@WebServlet**注解
- 在SpringBoot的主启动类上加上**@ServletComponentScan**注解
- 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!!!");
}
}
- 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);
}
}
- springboot应用启动
2.打开浏览器输入http://localhost:8066/springbootDemo/testOne,输出结果如下:
Hello,MyServletOne!!!
2. Filter(过滤器)注册
1. 以配置类方式注册Filter
- 自定义一个Filter类(如:MyFilter.java)让其实现Filter接口并实现相关方法
- 在配置类中注册 FilterRegistrationBean,设置过滤的URL等
- 编写测试案例进行过滤器测试
2. 以纯注解方式注册Filter
- 在在定义的Filter类中加入**@WebFilter**注解,并设置filterName及过滤的URL
- 在主启动类上加入 @ServletComponentScan注解
- 启动服务器进行测试
3. 以注解的方式注册Filter执行顺序不生效问题
-
问题描述,使用**@WebFilter方式注入filter后,用@Order**注解指定filter的执行顺序则不起作用
-
原因分析:
阅读源码发现:重点在ServletComponentHandler 处理带有注解WebFilter的类;handle方法中处理的attributes是@WebFilter的属性,因为@WebFilter本身是没有Order属性,所以构建的Filter将是默认的Order值,而上面源码可得知,类名可决定注册Filter的顺序(即Filter过滤顺序,因为此处只能注册默认的Order值)
- 解决方法:
- 以自定义的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
注解
- 编写自定义监听类如
RegListenerTwo
实现ApplicationListener
接口- 在自定义监听类上面标注
@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
注册监听
- 编写自定义监听类如
RegListenerTwo
实现ApplicationListener
接口- 在自定义监听类上面标注
@Component
注解- 在自定义类中编写一个监听方法,并在方法上标注
@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. 主启动配置监听
- 编写自定义监听类如
RegListenerOne
实现ApplicationListener
接口- 在主启动类上面标注
@ServletComponentScan
- 将自定义的监听类加入到SpringApplication的监听中
- 编写监听类
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====执行了");
}
}
- 直接启动类开启注解并添加自定义监听
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(拦截器)注册
- 自定义拦截器
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拦截器。。。。处理后");
}
}
- 注册拦截器
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. 执行顺序
注意: 监听器 、 过滤器、 拦截器 执行优先顺序如下
监听器 > 过滤器 > 拦截器
- 同时配置了Servlet,过滤器,拦截器,优先顺序如下
Servlet>Filter>Interceptor