SpringMVC源码--拦截器实现机制

  1. 前言

     如果框架源码看多了,就会发现一个问题,AOP的思想是存在于整个框架思想的。无论是Spring,还是SpringMVC,或者Mybatis、Hibernate。为什么呢?因为AOP的存在让我们更好地去控制程序走向,而且不用人为的编写大量重复性代码。比如一个简单的权限认证,我们肯定不希望在每个用户请求抵达服务器时都需要在业务功能中加入重复性的权限验证代码。无疑,对所有的请求进行拦截,只放行权限认证通过的请求才是最佳的实践。这就是AOP思想。拦截器的本质也是一种AOP实践。

     2.WebMvcConfigurationSupport 类的部分代码

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {

	private ServletContext servletContext;

	private ApplicationContext applicationContext;

	private List<Object> interceptors;

	private ContentNegotiationManager contentNegotiationManager;

	private List<HttpMessageConverter<?>> messageConverters;

	private PathMatchConfigurer pathMatchConfigurer;


	@Override
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}

	
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	
	@Bean
	public RequestMappingHandlerMapping requestMappingHandlerMapping() {}

	
	protected final Object[] getInterceptors() {
		if (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();
	}

	
	protected void addInterceptors(InterceptorRegistry registry) {
	}

	
	@Bean
	public HandlerMapping viewControllerHandlerMapping() {
		ViewControllerRegistry registry = new ViewControllerRegistry();
		addViewControllers(registry);

		AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
		handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping();
		handlerMapping.setPathMatcher(mvcPathMatcher());
		handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
		handlerMapping.setInterceptors(getInterceptors());
		return handlerMapping;
	}

	
	protected void addViewControllers(ViewControllerRegistry registry) {
	}

	@Bean
	public BeanNameUrlHandlerMapping beanNameHandlerMapping() {
		BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
		mapping.setOrder(2);
		mapping.setInterceptors(getInterceptors());
		return mapping;
	}

	@Bean
	public HandlerMapping resourceHandlerMapping() {
		ResourceHandlerRegistry registry = new ResourceHandlerRegistry(
				this.applicationContext, this.servletContext);
		addResourceHandlers(registry);
		AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
		handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping();
		handlerMapping.setPathMatcher(mvcPathMatcher());
		handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
		return handlerMapping;
	}

	protected void addResourceHandlers(ResourceHandlerRegistry registry) {
	}
	@Bean
	public ResourceUrlProvider mvcResourceUrlProvider() {
	
	}
	
	@Bean
	public HandlerMapping defaultServletHandlerMapping() {
		DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(servletContext);
		configureDefaultServletHandling(configurer);
		AbstractHandlerMapping handlerMapping = configurer.getHandlerMapping();
		handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping();
		return handlerMapping;
	}

}

3.WebMvcConfigurationSupport 类的使用

       通常为了使用拦截器,我们需要做两件事:

       1).定义一个拦截器

       public class MyInterceptor implements HandlerInterceptor{

             //接口方法实现

        }

       2)..注册拦截器

      public class MyInterceptorRegistry extends WebMvcConfigurationSupport {

               @Override

              protected void addInterceptors(InterceptorRegistry registry) {

                   registry.addInterceptor(new MyInterceptor());
              }

        }

 4.WebMvcConfigurationSupport 注册拦截器的实现过程

    WebMvcConfigurationSupport类中有这样两个方法:

protected final Object[] getInterceptors() {
    //如果interceptors为空,说明拦截器还没有注册过,需要注册
	if (interceptors == null) {
        //构造一个拦截器注册器
	InterceptorRegistry registry = new InterceptorRegistry();
        //调用子类实现的addInterceptors()方法
	addInterceptors(registry);
	registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
		registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
		this.interceptors = registry.getInterceptors();
	}
	return this.interceptors.toArray();
}

//WebMvcConfigurationSupport中的空方法,由子类实现
protected void addInterceptors(InterceptorRegistry registry) {
	
}

   可以看到,由getInterceptors()方法调用了我们自定义的MyInterceptor类中定义的addInterceptors()方法,从而将自定义拦截器注册到了WebMvcConfigurationSupport中。接下来呢,只要调用getInterceptors()方法,就能得到所有的拦截器了。我们可以看一看InterceptorRegistry类的内部:

public class InterceptorRegistry {

	private final List<InterceptorRegistration> registrations = new ArrayList<InterceptorRegistration>();

	public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
		InterceptorRegistration registration = new InterceptorRegistration(interceptor);
		registrations.add(registration);
		return registration;
	}

	public InterceptorRegistration addWebRequestInterceptor(WebRequestInterceptor interceptor) {
		WebRequestHandlerInterceptorAdapter adapted = new WebRequestHandlerInterceptorAdapter(interceptor);
		InterceptorRegistration registration = new InterceptorRegistration(adapted);
		registrations.add(registration);
		return registration;
	}

	protected List<Object> getInterceptors() {
		List<Object> interceptors = new ArrayList<Object>();
		for (InterceptorRegistration registration : registrations) {
			interceptors.add(registration.getInterceptor());
		}
		return interceptors ;
	}

}

  InterceptorRegistry类的内部维护了一个拦截器适配器的集合registrations ,我们的拦截器被转化为适配器对象来使用。但是getInterceptors()时得到的不是适配后的对象,而是拦截器本身对象的集合。

  


5.WebMvcConfigurationSupport 中拦截器集合的调用者

可以看到,WebMvcConfigurationSupport 类中的getInterceptors()方法被三个方法调用了。仔细观察,可以发现它们都在WebMvcConfigurationSupport类中。那么,我们来看看它们都是干什么用的:

    @Bean
	public BeanNameUrlHandlerMapping beanNameHandlerMapping() {
		BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
		mapping.setOrder(2);
		mapping.setInterceptors(getInterceptors());
		return mapping;
	}

    @Bean
	public RequestMappingHandlerMapping requestMappingHandlerMapping() {

		RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
		handlerMapping.setOrder(0);
		handlerMapping.setInterceptors(getInterceptors());
		handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());

		PathMatchConfigurer configurer = getPathMatchConfigurer();
		
		return handlerMapping;
	}

    @Bean
	public HandlerMapping viewControllerHandlerMapping() {
		ViewControllerRegistry registry = new ViewControllerRegistry();
		addViewControllers(registry);

		AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
		handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping();
		handlerMapping.setPathMatcher(mvcPathMatcher());
		handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
		handlerMapping.setInterceptors(getInterceptors());
		return handlerMapping;
	}

  发现没有,在Spring创建HandlerMapping类型的Bean事,getInterceptors()方法被调用了,然后把所有的拦截器加入了HandlerMapping对象中。
 

   总结:SpringMVC的拦截器是如此,Mybatis的拦截器也是如此。有一条清晰的线索一直贯穿其中,先定义一个接口作为规范,允许编码人员实现此接口来完成自定义操作。再把所有符合条件的接口实现类添加到一个容器中,供系统使用。也算是一种比较巧妙的设计吧。

  另一种思路是,在Spring容器完成所有的Bean的创建后,容器启动完成之前,获取实现了某种接口的所有实现类Bean,做一些特殊的事情。(ApplicationListener接口了解一下。。。)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值