title: 动手撸一个 mvc 框架4
date: 2020/04/26 10:54
本节内容
我们回到 tag2 看看拦截器是怎么被装配上的
Spring 4.0
我们接下来看 tag2 ,点进去
上图我们提出了 2 个问题,接下来我们来研究一下:
众所周知我们要自定义拦截器的时候需要实现 HandlerInterceptor 接口,假设我们开启了 @EnableMvc 并且通过配置类的方式对拦截器进行注册,如下图:
上图引出了一个叫 InterceptorRegistry 的东西,我们看下它是什么:
那么谁会调用 getInterceptors 方法呢:
那么问题来了,我们继承 WebMvcConfigurerAdapter 的那个类是在什么时候调用的呢?
我们在上面的代码中没有发现读取 xml 配置的拦截器,那是不是用了 @EnableMvc 注解,就不能使用 xml 配置的拦截器了?
当然不是,因为在 RequestMappingHandlerMapping 中拦截器采用的是 adaptedInterceptors 字段,而不是上面设置的 interceptors 字段。
我们开始吧
1、AbstractHandlerMapping 新增 getHandlerInternal 方法
public abstract class AbstractHandlerMapping implements HandlerMapping {
private List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();
...
private HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain handlerExecutionChain = new HandlerExecutionChain(handler);
for (HandlerInterceptor interceptor : adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
String lookupPath = request.getServletPath();
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath)) {
handlerExecutionChain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
// 当一个拦截器没有条件的时候会走这里
handlerExecutionChain.addInterceptor(interceptor);
}
}
return handlerExecutionChain;
}
/**
* 查找给定请求的处理程序,如果未找到特定请求,则返回 null。
*/
protected abstract Object getHandlerInternal(HttpServletRequest request);
public void setInterceptors(List<HandlerInterceptor> interceptors) {
adaptedInterceptors.addAll(interceptors);
}
}
2、拦截器接口
public interface HandlerInterceptor {
/**
* Controller执行前调用此方法
*/
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
// /**
// * Controller执行后但未返回视图前调用此方法
// */
// void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView);
/**
* Controller执行后且视图返回后调用此方法
*/
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
3、MappedInterceptor
/**
* Spring 中这里实现了 HandlerInterceptor 是因为 adaptedInterceptors 中有些不是 MappedInterceptor 的实现,而是 HandlerInterceptor
* <p>
* 这里可以理解为它采用了装饰者模式,动态的给 HandlerInterceptor 增加了 matches 方法
* <p>
* MappedInterceptor 与 InterceptorRegistration 之间是类似于 String 和 StringBuilder 之间的关系
* <p>
* MappedInterceptor 也是不可变对象
*
* @author yujx
* @date 2020/04/26 11:10
*/
public final class MappedInterceptor implements HandlerInterceptor {
private final HandlerInterceptor interceptor;
private final List<String> includePatterns;
private final List<String> excludePatterns;
public MappedInterceptor(HandlerInterceptor interceptor, List<String> includePatterns, List<String> excludePatterns) {
this.interceptor = interceptor;
this.includePatterns = includePatterns;
this.excludePatterns = excludePatterns;
}
// 全部 return true 了,不想写逻辑
public boolean matches(String lookupPath) {
return true;
}
public HandlerInterceptor getInterceptor() {
return interceptor;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return interceptor.preHandle(request, response, handler);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
interceptor.afterCompletion(request, response, handler, ex);
}
}
4、InterceptorRegistry
/**
* 拦截器注册中心
*
* @author yujx
* @date 2020/04/26 13:11
*/
public class InterceptorRegistry {
private final List<InterceptorRegistration> registrations = new ArrayList<>();
/**
* 添加拦截器
*/
public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
InterceptorRegistration registration = new InterceptorRegistration(interceptor);
registrations.add(registration);
return registration;
}
/**
* 返回所有注册的拦截器。
*/
protected List<HandlerInterceptor> getInterceptors() {
List<HandlerInterceptor> interceptors = new ArrayList<>();
for (InterceptorRegistration registration : registrations) {
interceptors.add(registration.getInterceptor());
}
return interceptors ;
}
}
5、MappedInterceptor 的“伙伴”
public class InterceptorRegistration {
private final HandlerInterceptor interceptor;
private final List<String> includePatterns = new ArrayList<>();
private final List<String> excludePatterns = new ArrayList<>();
public InterceptorRegistration(HandlerInterceptor interceptor) {
this.interceptor = interceptor;
}
public InterceptorRegistration addPathPatterns(String... patterns) {
this.includePatterns.addAll(Arrays.asList(patterns));
return this;
}
public InterceptorRegistration excludePathPatterns(String... patterns) {
this.excludePatterns.addAll(Arrays.asList(patterns));
return this;
}
public HandlerInterceptor getInterceptor() {
// 如果 includePatterns 和 excludePatterns 都是空的,则直接返回这个拦截器
if (CollectionUtil.isEmpty(includePatterns) && CollectionUtil.isEmpty(excludePatterns)) {
return interceptor;
}
// Spring 中在这里将其转换成了数组,目的是为了让其不可变
return new MappedInterceptor(interceptor, includePatterns, excludePatterns);
}
}
6、可以让用户添加拦截器的
public interface WebMvcConfigurer {
default void addInterceptors(InterceptorRegistry registry) {
}
}
7、配置类及其相关类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
/**
* 为什么要使用 WebMvcConfigurerComposite 作为 WebMvcConfigurer 集合的容器,并且采用组合模式?
* <p>
* 可能是为了更面向对象一点吧
*
* @author yujx
* @date 2020/04/26 13:25
*/
public class DelegatingWebMvcConfiguration implements ApplicationContextAware, InitializingBean {
private ApplicationContext applicationContext;
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
handlerMapping.setInterceptors(getInterceptors());
return handlerMapping;
}
private List<HandlerInterceptor> getInterceptors() {
InterceptorRegistry registry = new InterceptorRegistry();
configurers.addInterceptors(registry);
return registry.getInterceptors();
}
@Override
public void setApplicationContext(ApplicationContext ctx) {
this.applicationContext = ctx;
}
// 当这个对象初始化完成后调用
@Override
public void afterPropertiesSet() {
Collection<WebMvcConfigurer> configurers = applicationContext.getBeansOfType(WebMvcConfigurer.class).values();
this.configurers.addWebMvcConfigurers(configurers);
}
}
class WebMvcConfigurerComposite implements WebMvcConfigurer {
private final List<WebMvcConfigurer> delegates = new ArrayList<>();
@Override
public void addInterceptors(InterceptorRegistry registry) {
for (WebMvcConfigurer mvcConfigurer : delegates) {
mvcConfigurer.addInterceptors(registry);
}
}
public void addWebMvcConfigurers(Collection<WebMvcConfigurer> configurers) {
delegates.addAll(configurers);
}
}