SpringBoot项目启动过程动态修改接口请求路径
背景
最近遇到一个技术需求,需要对其他多个已有的服务进行整合打包为一个整体的服务,项目启动过程发现一个问题,在controller层多个服务之间存在相同的RequestMapping接口请求路径,导致服务无法启动。
目前的接口定义规范为:/服务名(context-path)/接口版本号/模块名/接口名
例如通过用户Id查询用户信息的接口,在统一认证服务和用户管理服务有如下接口定义
统一认证服务:/sso/v1.0/user/get/{id}
用户管理服务:/user/v1.0/user/get/{id}
当我们把统一认证服务和用户管理服务进行整合为一个服务时,/v1.0/user/get/{id}请求路径发生重复,导致服务无法启动。
解决方案
为了解决服务之间接口定义冲突的问题,我们准备对接口的请求路径进行动态修改,主要是通过controller类所在的包路径进行服务名的识别,并加入到接口请求路径的最前面。
举个栗子:
统一认证服务controller层伪代码如下:
package cn.codest.sso.web; @RestController
@Api(tags = "统一认证服务")
@RequestMapping("/v1.0/user")
@RequiredArgsConstructor
public class SSOController { private final UserService userService; @GetMapping("/get/{id}")
@ApiOperation(value = "用户查询", httpMethod = "GET", notes = "用户查询")
public SwaggerResultUtil getById(String id){
return SwaggerResultUtil.resultSuccess(userService.get(id));
} }
通过重载RequestMappingHandlerMapping类的getMappingForMethod方法,实现在项目启动过程中注册/v1.0/user/get/{id}接口时,识别package的路径cn.codest.sso.web提取业务标识sso,修改接口注册地址为/sso/v1.0/user/get/{id},具体代码如下:
@Slf4j
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class PackagePathRequestMappingHandler extends RequestMappingHandlerMapping { private static final String PACKAGE_PREFIX = "cn.codest"; private static final String SERVICE_PREFIX = "service"; private static final String PROVIDER_PREFIX = "providerD"; /**
* 包名对应的服务名缓存类
*/
private final LinkedHashMap<String, String> services = new LinkedHashMap<>(8); @Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { // 判断当前注册的controller接口属于业务层controller,部分中间件例如swagger也会进行接口注册
if (!StringUtils.startsWith(handlerType.getName(), PACKAGE_PREFIX)
|| !AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class)
|| AnnotatedElementUtils.hasAnnotation(handlerType, FeignClient.class)) {
return super.getMappingForMethod(method, handlerType);
} try {
// 构造RequestMapping对象
RequestMappingInfo mapping = super.getMappingForMethod(method, handlerType);
// 根据包路径获取服务名
String serviceName = getServiceName(handlerType.getName());
if (StringUtils.isBlank(serviceName)) {
return mapping;
}
// 增加服务名前缀
return RequestMappingInfo.paths(serviceName).build().combine(mapping);
} catch (Exception e) {
log.error("重写RequestMapping请求路径时发生错误[class: {}, method: {}]", handlerType.getName(), method.getName(), e);
throw e;
}
} protected String getServiceName(String className) {
// 分割类限定名
String[] packages = className.split("\\."); // 判断包路径长度
if (packages.length > 3) {
// 获取子产品包名
String serviceName = packages[2]; // 读取缓存
if (services.containsKey(serviceName)) {
return services.get(serviceName);
} else if (StringUtils.startsWith(serviceName, SERVICE_PREFIX)) { // service服务
services.put(serviceName, serviceName.replace(SERVICE_PREFIX, StringUtils.EMPTY));
} else if (StringUtils.startsWith(serviceName, PROVIDER_PREFIX.toLowerCase())) { // provider服务
services.put(serviceName, serviceName.replace(PROVIDER_PREFIX.toLowerCase(), PROVIDER_PREFIX));
} return services.get(serviceName);
} return StringUtils.EMPTY;
} }
注册自定义RequestMappingHandler,项目使用的SpringBoot版本为2.0.x,不同版本注册方式不同,可以自行查阅官方文档。
public class CustomWebMvcConfig implements WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new PackagePathRequestMappingHandler();
handlerMapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
return handlerMapping;
}
}
SpringBoot项目启动过程动态修改接口请求路径的更多相关文章
- springboot 项目启动后访问不论什么请求的是spring的注册页面Please sign in Username || springboot禁用security
解决方法: 1.在启动类上添加注解@EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class}) 2.或者:@SpringB ...
- SpringBoot项目启动后再请求远程接口的实现方式
场景 有一个SpringBoot项目需要在启动后请求另一个远程服务拿取配置,而不是加载过程中去请求,可能会出现类没有实例化的场景,因此需要实现项目完全启动后再进行请求的场景. 解决 一般会有两种实现方 ...
- Spring Boot启动过程及回调接口汇总
Spring Boot启动过程及回调接口汇总 链接: https://www.itcodemonkey.com/article/1431.html 来自:chanjarster (Daniel Qia ...
- ssm框架中,项目启动过程以及web.xml配置详解
原文:https://blog.csdn.net/qq_35571554/article/details/82385838 本篇主要在基于SSM的框架,深入讲解web.xml的配置 web.xml ...
- Springboot 项目启动后执行某些自定义代码
Springboot 项目启动后执行某些自定义代码 Springboot给我们提供了两种"开机启动"某些方法的方式:ApplicationRunner和CommandLineRun ...
- SpringBoot源码分析之SpringBoot的启动过程
SpringBoot源码分析之SpringBoot的启动过程 发表于 2017-04-30 | 分类于 springboot | 0 Comments | 阅读次数 SpringB ...
- springboot项目启动成功后执行一段代码的两种方式
springboot项目启动成功后执行一段代码的两种方式 实现ApplicationRunner接口 package com.lnjecit.lifecycle; import org.springf ...
- springboot项目启动之后初始化自定义配置类
前言 今天在写项目的时候,需要再springboot项目启动之后,加载我自定义的配置类的一些方法,百度了之后特此记录下. 正文 方法有两种: 1. 创建自定义类实现 CommandLineRunner ...
- springBoot项目启动类启动无法访问
springBoot项目启动类启动无法访问. 网上也查了一些资料,我这里总结.下不来虚的,也不废话. 解决办法: 1.若是maven项目,则找到右边Maven Projects --->Plug ...
- SpringBoot项目启动时链接数据库很慢
SpringBoot项目启动时链接数据库很慢 springboot项目在启动时候,如下图所示,链接数据库很慢 解决方法:在mysql 的配置文件中 配置 skip-name-resolve
随机推荐
- Go面经 | 成都Go面试这么卷?卷王介绍:游戏行业 3年经验 20k+
Go最新面经分享:算法.并发模型.缓存落盘.etcd.actor模型.epoll等等... 本文先分享2段面经,文末总结了关键问题的复盘笔记.一定要看到最后! 求职者情况 分享一下好友的最新面经. 简 ...
- 用Python语言进行多元时间序列ARIMAX模型分析
1.ARIMAX模型定义 ARIMAX模型是指带回归项的ARIMA模型,又称扩展的ARIMA模型.回归项的引入有利于提高模型的预测效果.引入的回归项一般是与预测对象(即被解释变量)相关程度较高的变量. ...
- 《最新出炉》系列初窥篇-Python+Playwright自动化测试-14-playwright操作iframe-番外篇
1.简介 通过前边三篇的学习,想必大家已经对iframe有了一定的认识和了解,今天这一篇主要是对iframe的一些特殊情况的介绍和讲解,主要从iframe的定位.监听事件和执行js脚本三个方面进行展开 ...
- 淘宝详情api接口的应用
淘宝详情API接口是一个基于HTTP协议的接口服务,可用于获取淘宝商品的具体信息.下面将介绍如何调用淘宝详情API接口获取淘宝商品数据的步骤. 1.注册账号并创建应用 首先,我们需要进行账号注册.实名 ...
- 使用Springboot+SpringCloud+Seata1.3.0+Nacos1.2.1进行全局事务管理
一.官方文档网址 http://seata.io/zh-cn/docs/overview/what-is-seata.html Seata1.3.0开发组提供的开发文档 二.常见问题 2.1:网址: ...
- java中有哪些并发的List?只知道一种的就太逊了
java中有很多list,但是原生支持并发的并不多,我们在多线程的环境中如果想同时操作同一个list的时候,就涉及到了一个并发的过程,这时候我们就需要选择自带有并发属性的list,那么java中的并发 ...
- POWERBI_1分钟学会_连续上升或下降指标监控
一:数据源 模拟数据为三款奶茶销量的日销售数据源,日期是23.8.24-23.8.31.A产品为连续7天,日环比下降,B产品为连续3天,日环比下降,C产品为连续2天,日环比下降. 二:建立基础度量值 ...
- SQL函数升序Asc,降序Desc使用总结
关键字-升序Asc及降序Desc的使用语法 对某一结果集按列进行升序或降序排列即:结果集 Order by 列名/数字 Asc/Desc. 一.Asc,Desc排序讲以下5点 1.不写关键字Asc/D ...
- RocketMQ版控制台,在左侧
打开IntelliJ IDEA,创建一个Java工程. 在pom.xml文件中添加以下依赖引入Java SDK的依赖库. <dependency> <groupId>org ...
- 17.2 实现无管道正向CMD
WSASocket 无管道正向CMD,使用WSASocket函数创建一个TCP套接字,并绑定到一个本地地址和端口上.然后使用CreateProcess函数创建一个新的CMD进程,并将标准输入.输出和错 ...