在 Spring MVC容器启动时——web九大组件初始化 已经大概介绍过web九大组件,本文将聚焦于Spring MVC中最重要的一个组件:HandlerMapping展开讨论。
HandlerMapping
用来查找Handler的。在SpringMVC中会有很多请求,每个请求都需要一个Handler处理,具体接收到一个请求之后使用哪个Handler进行处理呢?这就是HandlerMapping需要做的事。
HandlerMapping:负责映射用户的URL和对应的处理类Handler,HandlerMapping并没有规定这个URL与应用的处理类如何映射。所以在HandlerMapping接口中仅仅定义了根据一个URL必须返回一个由HandlerExecutionChain代表的处理链,我们可以在这个处理链中添加任意的HandlerAdapter实例来处理这个URL对应的请求(这样保证了最大的灵活性映射关系)。
public interface HandlerMapping { //@since 4.3.21 String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler"; String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping"; String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern"; String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping"; String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables"; String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables"; String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes"; // 该接口提供的唯一一个方法~~~~ @Nullable HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
看看它的继承树:
它有两大继承主线:MatchableHandlerMapping和AbstractHandlerMapping。
AbstractHandlerMapping
这是Spring的常用模式了,一言不合就先来个抽象实现。查看它的继承图谱:
有必要先对两个XXXSupport进行一个非常简单的说明~
WebApplicationObjectSupport和ApplicationObjectSupport
看它们的声明,它们更像是ApplicationContextAware和ServletContextAware的适配器。
public abstract class ApplicationObjectSupport implements ApplicationContextAware { ... } public abstract class WebApplicationObjectSupport extends ApplicationObjectSupport implements ServletContextAware { ... }
所以如果我们在继承允许的情况下,只需要继承此类就能自动拥有上面两个接口的功能了。
@Service public class HelloServiceImpl extends WebApplicationObjectSupport implements HelloService { @Override public Object hello() { // 继承自ApplicationObjectSupport就可以很方便的获取到下面这两个值 System.out.println(super.getApplicationContext()); System.out.println(super.obtainApplicationContext()); //@since 5.0 // MessageSourceAccessor参考:MessageSourceAware 它是对MessageSource的一个包装 处理国际化 System.out.println(super.getMessageSourceAccessor()); // 这里需要继承和web相关的:WebApplicationObjectSupport System.out.println(super.getWebApplicationContext()); System.out.println(super.getServletContext()); System.out.println(super.getTempDir()); //Tomcat9_demowar\work\Catalina\localhost\demo_war_war return "service hello"; } @Override protected void initApplicationContext() throws BeansException { // 这是父类提供给子类的(父类为空实现~),子类可以自行实现,实现子类的逻辑 // 比如子类AbstractDetectingUrlHandlerMapping就复写了此方法去detectHandlers(); super.initApplicationContext(); } }
就这样可以通过继承的方式快速的实现获取上下文等,推荐使用~~~
WebApplicationObjectSupport用于提供上下文ApplicationContext和ServletContext的功能~
很显然如果你已经有继承了,那就没办法只能选择实现接口的方式了~
继续来看看AbstractHandlerMapping这个抽象实现给我们做了哪些事情~