spring 拦截器配置

spring boot拦截器

自定义拦截器

Interceptor定义

方法说明
preHandle在实际的Handle执行前执行
postHandleHandle执行后视图渲染前执行
afterCompletionHandle执行且视图渲染完成后执行

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了。

转载:https://blog.csdn.net/icarusliu/article/details/78833520

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值