spring boot拦截器
自定义拦截器
Interceptor定义
方法 | 说明 |
---|---|
preHandle | 在实际的Handle执行前执行 |
postHandle | Handle执行后视图渲染前执行 |
afterCompletion | Handle执行且视图渲染完成后执行 |
Spring为方便使用实现了HandlerInterceptorAdapter的抽象类;需要实现的方法都实现为空的方法,在使用时只需实现必要的方法即可。
class TestInterceptor extends HandlerInterceptorAdapter {
private val logger = LoggerFactory.getLogger(HandlerInterceptorAdapter::class.java)
/**
* This implementation always returns `true`.
*/
@Throws(Exception::class)
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
if (logger.isDebugEnabled) {
logger.debug("TestInterceptor preHandle begin to execute!")
}
return true
}
/**
* This implementation is empty.
*/
@Throws(Exception::class)
override fun postHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any,
@Nullable modelAndView: ModelAndView?) {
if (logger.isDebugEnabled) {
logger.debug("TestInterceptor postHandle begin to execute!")
}
}
/**
* This implementation is empty.
*/
@Throws(Exception::class)
override fun afterCompletion(request: HttpServletRequest, response: HttpServletResponse, handler: Any,
@Nullable ex: Exception?) {
if (logger.isDebugEnabled) {
logger.debug("TestInterceptor afterCompletion begin to execute!")
}
}
/**
* This implementation is empty.
*/
@Throws(Exception::class)
override fun afterConcurrentHandlingStarted(request: HttpServletRequest, response: HttpServletResponse,
handler: Any) {
if (logger.isDebugEnabled) {
logger.debug("TestInterceptor afterConcurrentHandlingStarted begin to execute!")
}
}
}
拦截器定义
拦截器定义完成后,还需要将拦截器引入,并指定该拦截器所拦截的场景。
在SpringBoot中,一般通过使用EnableWebMvc及Configuration两个注解,并实现WebMvcConfigurer接口来添加拦截器,实现代码如下:
@EnableWebMvc
@Configuration
class WebConfig: WebMvcConfigurer {
override fun addInterceptors(registry: InterceptorRegistry) {
registry.addInterceptor(TestInterceptor()).addPathPatterns("/**")
}
}
定义Controller
@RestController
@RequestMapping("/test")
class TestController {
private val logger = LoggerFactory.getLogger(TestController::class.java)
@RequestMapping("/test")
fun test(): String {
if (logger.isDebugEnabled) {
logger.debug("Test controller begin to execute!")
}
logger.info("Test!")
if (logger.isDebugEnabled) {
logger.debug("Test controller execution has been completed!")
}
return "test";
}
}
配置分析
EnableWebMvc
与Configuration注解结合,可从WebMvcConfigurationSupport中引入SpringMVC的相关配置;如果需要修改引入的配置,需要通过实现WebMvcConfigurer接口提供的方法来进行。
注解EnableWebMvc在一个工程中只能注解在一个类上; 但实现WebMvcConfigurer的类可以有多个。
EnableWebMvc是如何引入WebMvcConfigurationSupport中的相关配置的呢?
我们来看下其本身实现:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
可以看到其通过Import引入了DelegatingWebMvcConfiguration配置类, 而这个类又继承了WebMvcConfigurationSupport类。
WebMvcConfigurer
WebMvcConfigurer主要是提供接口来实现SpringMVC的自定义配置,其中它与Interceptor相关的就是addInterceptors方法,通过覆盖该方法,可以添加自定义Interceptor。
addInterceptors返回类型为InterceptorRegistration对象,通过查看该类实现,看到其提供的主要方法是: addPathPatterns/excludePathPatterns/pathMatcher/order,主要完成两个功能:一是提供配置所添加的Interceptor的映射路径的方法;二是提供配置所添加的Interceptor的Order的方法,通过Order可控制所添加的Interceptor在所有Interceptors中的执行顺序:
override fun addInterceptors(registry: InterceptorRegistry) {
registry.addInterceptor(TestInterceptor())
.addPathPatterns("/**")
.order(1000)
}
拦截器生效实现
拦截器查询源码:
查找过程在AbstractHandlerMapping中实现,实际查找拦截器在方法getHandlerExecutionChain中:
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
adaptedInterceptors属性是如何初始化:
通过分析AbstractHandlerMapping类,其adaptedInterceptors属性实际是在initInterceptors方法中根据interceptors来进行初始化的。现在的问题转变成interceptors这个属性是如何初始化的了。 实际上这个属性是通过setInterceptors方法来设置。
通过@EnableWebMvc注解实际上引入了DelegatingWebMvcConfiguration这个类;查看这个类,在其中有一方法被Autowired注解:
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
在此处,我们自定义的继承自WebMvcConfigurer的类会被注入。
再查看 DelegatingWebMvcConfiguration 这个类,它继承了 WebMvcConfigurationSupport 类。分析WebMvcConfigurationSupport,可以看到以下方法:
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
if (useSuffixPatternMatch != null) {
mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
}
if (useRegisteredSuffixPatternMatch != null) {
mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
}
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
UrlPathHelper pathHelper = configurer.getUrlPathHelper();
if (pathHelper != null) {
mapping.setUrlPathHelper(pathHelper);
}
PathMatcher pathMatcher = configurer.getPathMatcher();
if (pathMatcher != null) {
mapping.setPathMatcher(pathMatcher);
}
return mapping;
}
可以看到RequestMappingHandlerMapping类被注入Spring容器。
同时通过mapping.setInterceptors(getInterceptors())将所有的Interceptors设置到HandperMapping对象中 。
这样就找到了ReuqestMappingHandlerMapping的setInterceptors方法调用处了。
接下来的问题就是此处调用的getInterceptors方法的实现。
protected final Object[] getInterceptors() {
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
此处如果interceptors对象为空时,会调用addInterceptors方法;其实现在DelegatingWebMvcConfiguration类中:
@Override
protected void addInterceptors(InterceptorRegistry registry) {
this.configurers.addInterceptors(registry);
}
在前文已经描述到,DelegatingWebMvcConfiguration类中的configurers属性会将所有继承了WebMvcConfigurer的配置类全部添加进去。如我们自定义的配置类;在此处调用DelegatingWebMvcConfiguration的addInterceptors方法时,实际就是调用各个WebMvcConfigurer对象的addInterceptors方法来完成自定义的Interceptor注册过程。
通过这一系列过程,RequestMappingHandlerMapping的getInterceptors方法就可以获取到所有自定义的Interceptor了。