spring MVC之自定义动态路由

简单回顾spring MVC

  1. DispatcherServletAutoConfiguration自动注册DispatcherServlet bean
  2. DispatcherServletRegistrationConfiguration基于DispatcherServlet bean自动注册Servlet注册器 bean:ServletRegistrationBean
  3. JettyEmbeddedWebAppContext设置ServletContextInitializerConfiguration,ServletContextInitializerConfiguration基于ServletContextInitializer bean构建,作为Handler注册为由Jetty的Server实例所管理的bean,Server启动前先启动它所管理的bean,即包含启动JettyEmbeddedWebAppContext,调用父类:WebAppContext.doStart,启动上下文
  4. 配置前置动作WebAppContext.preConfigure
  5. 调用父类启动动作:ContextHandler.doStart。启动上下文:startContext,调用子类重写的WebAppContext.startContext
  6. 遍历_configurations执行配置:ServletContextInitializerConfiguration.configure。将ServletContextInitializerConfiguration.Initializer添加至WebAppContext上下文的可管理bean,此时上下文正处于启动中,因此立即启动Initializer
  7. 启动Initializer.doStart,回调ServletContextInitializer.onStartup。即:EmbeddedWebApplicationContext.getSelfInitializer方法中创建的匿名实现类ServletContextInitializer直接回调EmbeddedWebApplicationContext.selfInitialize
  8. EmbeddedWebApplicationContext.selfInitialize通过ServletContextInitializerBeans获取并排序ServletContextInitializer bean集合后遍历工厂中ServletContextInitializer bean回调onStartup
  9. 回调ServletContextInitializer bean实现类之一(其他实现例如:FilterRegistrationBean、ServletListenerRegistrationBean等):ServletRegistrationBean.onStartup
  10. DispatcherServlet自动注册bean将该Servlet即mapping映射(默认为根:/)注册至Servlet上下文
  11. 由DispatcherServlet转发所有的web请求至对应RequestMapping映射的业务处理类

DispatcherServlet

  1. 父类doGet、doPost都会直接转至子类DispatcherServlet.doService处理
  2. doService转至org.springframework.web.servlet.DispatcherServlet#doDispatch处理
  3. 根据Request请求获取业务处理类句柄org.springframework.web.servlet.DispatcherServlet#getHandler
  4. 遍历org.springframework.web.servlet.DispatcherServlet#handlerMappings根据Request请求获取处理链org.springframework.web.servlet.HandlerMapping#getHandler

org.springframework.web.servlet.DispatcherServlet#handlerMappings

  1. 该句柄映射在spring应用上下文刷新完成时进行初始化
  2. org.springframework.web.servlet.FrameworkServlet.ContextRefreshListener#onApplicationEvent该监听器回调子类初始化策略:org.springframework.web.servlet.DispatcherServlet#initStrategies
  3. 初始化句柄映射:org.springframework.web.servlet.DispatcherServlet#initHandlerMappings

初始化句柄映射

  1. 如果org.springframework.web.servlet.DispatcherServlet#detectAllHandlerMappings为true并且工厂中存在HandlerMapping bean则使用HandlerMapping的bean列表作为句柄映射
  2. 否则,指定bean名称:handlerMapping,类型HandlerMapping为句柄映射
  3. 否则,从DispatcherServlet.properties配置中获取key=org.springframework.web.servlet.HandlerMapping的配置为句柄映射

RequestMappingHandlerMapping

org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration自动配置org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.EnableWebMvcConfiguration#requestMappingHandlerMapping句柄映射处理逻辑

  1. 调用父类方法构建句柄映射:org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerMapping
  2. 调用子类重写方法创建句柄映射:org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#createRequestMappingHandlerMapping
  3. 如果org.springframework.beans.factory.ObjectProvider#getIfUnique不为空则调用org.springframework.boot.autoconfigure.web.WebMvcRegistrations#getRequestMappingHandlerMapping返回RequestMappingHandlerMapping,否则调用父类方法创建:org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#createRequestMappingHandlerMapping,直接无参构造器构建
  4. 设置mapping order顺序为0
  5. 设置拦截器:org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getInterceptors,等等一系列设置
  6. 获取路径匹配配置:org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getPathMatchConfigurer
  7. 设置是否使用后缀模式匹配,默认为true,例如:路径"/users"与路径"/users.*"映射的业务逻辑均是匹配的
  8. 设置是否使用已注册的后缀模式匹配,默认为false,后缀模式匹配仅针对显示用ContentNegotiationManager注册的后缀生效。例如:.json,.html等显示注册的后缀
  9. 设置是否使用结尾为"/“斜划线情况的匹配,默认为true,例如:”/users" 与 "/users/"均匹配
  10. 设置url路径工具类,默认为空,工具类由配置类提供:org.springframework.web.servlet.config.annotation.PathMatchConfigurer#getUrlPathHelper

根据请求获取业务处理句柄类

假定RequestMappingHandlerMapping句柄映射处理

  1. 根据Request请求调用父类方法获取:org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
  2. 根据Request请求获取句柄内部处理类:org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerInternal,钩子方法由子类实现具体逻辑
  3. 如果为空则获取默认句柄处理类,默认为null:org.springframework.web.servlet.handler.AbstractHandlerMapping#getDefaultHandler

如果以上三种均没有找到对应的业务处理类,则抛出404异常页面或者如果设置throwExceptionIfNoHandlerFound为true则抛出NoHandlerFoundException类型异常

根据请求获取内部业务处理句柄类

根据下图中的HandlerMapping模型,可以确定子类实现类为:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal

1

根据请求获取业务处理句柄类。调用父类org.springframework.web.servlet.handler.AbstractHandlerMapping#getUrlPathHelper方法获取Url路径工具类,默认实现为:org.springframework.web.util.UrlPathHelper

// 父类:AbstractHandlerMapping,默认getUrlPathHelper为:UrlPathHelper
private UrlPathHelper urlPathHelper = new UrlPathHelper();
public UrlPathHelper getUrlPathHelper() {
	return urlPathHelper;
}
// 子类:AbstractHandlerMethodMapping
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 根据请求获取需要查找的url路径
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	if (logger.isDebugEnabled()) {
		logger.debug("Looking up handler method for path " + lookupPath);
	}
	this.mappingRegistry.acquireReadLock();
	try {
        // 根据url路径获取对应业务处理类的具体方法
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		if (logger.isDebugEnabled()) {
			if (handlerMethod != null) {
				logger.debug("Returning handler method [" + handlerMethod + "]");
			}
			else {
				logger.debug("Did not find handler method for [" + lookupPath + "]");
			}
		}
        // 返回对应业务类的业务处理方法
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		this.mappingRegistry.releaseReadLock();
	}
}

总结

url与业务处理方法的映射关系通过HandlerMapping接口实现类维护,spring通过该实现类获取对应的handler进行业务处理。如果我们想要自定义动态的路由可以通过该扩展点进行入手,并且目前我们的生产线上也已经正式投入使用,简直不要太好用。生产的案例如下:

功能描述

app端请求网关http服务,路径均加了一个版本号例如:/myurl/v92/getFoodInfo。如果app没有升级到92版本是看不到该路径方法的,只有新升级的92或者93、94版本才能使用该路径获取相关食品信息。可以通过此方式进行版本灰发控制,仅给部分用户提供新版本安装包进行更新安装后可以使用新功能,其他老版本app不会受影响,因为代码仅修改了92版本的业务逻辑,92以下的版本业务逻辑是没有任何代码改动的。通过该方式可以有效的规避升级风险

实现方法

配置自定义RequestMapping句柄映射

@Configuration
public class WebMvcConfig extends WebMvcRegistrationsAdapter {
    public WebMvcConfig() {
    }
	@Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new CustomRequestMappingHandlerMapping();
    }
}

自定义RequestMapping句柄映射中重写获取Url路径工具类方法,返回自定义的工具类

public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    ...
    @PostConstruct
    public void init() throws Exception {
        // 自定义的url路径版本映射逻辑
        this.urlPathHelper = new CustomUrlPathHelper(this.versionManager.getVersionMap());
    }
	@Override
    public UrlPathHelper getUrlPathHelper() {
        return this.urlPathHelper;
    }
	...
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Springboot: 1.什么是spring boot 1 2.spring boot的优点 2 3.环境搭建 3 3.1 添加依赖 3 3.2 创建目录和配置文件 4 3.3 创建启动类 5 3.4 案例演示 5 4 . 配置介绍 6 4.1 Spring boot 配置文件 6 4.2 配置文件内容 7 4.3属性使用 9 5 . Spring boot 基础包 10 6. spring boot 分解 11 6.1 提供 Spring MVC自动配置 11 6.2 对静态资源的支持 11 6.3 模板引擎 12 6.3.1 Thymeleaf模板引擎 12 ....... Springcloud: 通过整合SpringMVC+SpringBoot+Mybatis构建一个可用的基于SpringCloud的微服务工程将上述技术组件逐步落地,让大家看得懂做得出学得会。 00、硅谷学习_SpringBoot_源码、课件 01.硅谷学习_SpringCloud_前提概述 02.硅谷学习_SpringCloud_大纲概览 03.硅谷学习_SpringCloud_从面试题开始 04.硅谷学习_SpringCloud_微服务是什么 05.硅谷学习_SpringCloud_微服务是什么2 06.硅谷学习_SpringCloud_微服务与微服务架构 07.硅谷学习_SpringCloud_微服务优缺点 08.硅谷学习_SpringCloud_微服务技术栈有哪些 09.硅谷学习_SpringCloud_为什么选择SpringCloud作为微服务架构 10.硅谷学习_SpringCloud_SpringCloud是什么 11.硅谷学习_SpringCloud_SpringCloud_VS_SpringBoot区别对比 12.硅谷学习_SpringCloud_SpringCloud_VS_Dubbo区别对比 13.硅谷学习_SpringCloud_SpringCloud功能域和官网资料介绍 14.硅谷学习_SpringCloud_SpringCloud国内使用情况 15.硅谷学习_SpringCloud_Rest微服务案例-总体概述 16.硅谷学习_SpringCloud_Rest微服务案例-父工程构建步骤 17.硅谷学习_SpringCloud_Rest微服务案例-API公共模块和部门Entity步骤 18.硅谷学习_SpringCloud_Rest微服务案例-部门服务提供者 19.硅谷学习_SpringCloud_Rest微服务案例-部门服务消费者 20.硅谷学习_SpringCloud_Eureka是什么 21.硅谷学习_SpringCloud_EurekaServer服务注册中心建立 22.硅谷学习_SpringCloud_将已有的部门微服务注册进Eureka服务中心 23.硅谷学习_SpringCloud_微服务完善_主机映射名称修改 24.硅谷学习_SpringCloud_微服务完善_主机IP信息提示 25.硅谷学习_SpringCloud_微服务完善_info内容构建 26.硅谷学习_SpringCloud_Eureka自我保护机制介绍 27.硅谷学习_SpringCloud_Eure服务发现 28.硅谷学习_SpringCloud_Eureka集群配置 29.硅谷学习_SpringCloud_Eureka比Zookeeper好在哪里 30.硅谷学习_SpringCloud_Ribbon是什么 31.硅谷学习_SpringCloud_Ribbon配置初步 32.硅谷学习_SpringCloud_Ribbon负载均衡 33.硅谷学习_SpringCloud_Ribbon核心组件IRule 34.硅谷学习_SpringCloud_自定义Ribbo的负载均衡策略(上) 35.硅谷学习_SpringCloud_自定义Ribbo的负载均衡策略(下) 36.硅谷学习_SpringCloud_Feign是什么 37.硅谷学习_SpringCloud_Feign工程构建 38.硅谷学习_SpringCloud_Hystrix断路器是什么 39.硅谷学习_SpringCloud_服务熔断 40.硅谷学习_SpringCloud_服务降级 41.硅谷学习_SpringCloud_服务降级熔断小总结 42.硅谷学习_SpringCloud_豪猪hystrixDashboard 43.硅谷学习_SpringCloud_如何查看hystrixDashboard 44.硅谷学习_SpringCloud_Zuul是什么 4

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值