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
随机推荐
- 操作过滤器—MVC中使用操作过滤器实现JWT权限认证
前言 上一篇文章分享了授权过滤器实现JWT进行鉴权,文章链接:授权过滤器-MVC中使用授权过滤器实现JWT权限认证,接下来将用操作过滤器实现昨天的JWT鉴权. 一.什么是操作过滤器? 与授权过滤器 ...
- 知识图谱(Knowledge Graph)- Neo4j 5.10.0 Desktop & GraphXR
下载地址:https://neo4j.com/download/ 安装 下载时会产生激活码(保存下来) 下载完成后安装 运行后,输入激活码 进入主页面 运行自带的电影知识谱图测试是否安装成功 安装 G ...
- 渗透小tis
知己知彼,百战不殆 1.如果提示缺少参数,如{msg:params error},可尝使用字典模糊测试构造参数,进一步攻击. 2.程序溢出,int最大值为2147483647,可尝试使用该值进行整数溢 ...
- MindSponge分子动力学模拟——安装与使用(2023.08)
技术背景 昇思MindSpore是由华为主导的一个,面向全场景构建最佳昇腾匹配.支持多处理器架构的开放AI框架.MindSpore不仅仅是软件层面的工具,更重要的是可以协同华为自研的昇腾Ascend平 ...
- Deno 中使用 @typescript/vfs 生成 DTS 文件
背景 前段时间开源的 STC 工具,这是一个将 OpenApi 规范的 Swagger/Apifox 文档转换成代码的工具.可以在上一篇(<OpenApi(Swagger)快速转换成 TypeS ...
- 《Linux基础》04. 用户管理 · 用户组 · 相关文件 · 权限管理
@ 目录 1:用户管理指令 1.1:添加用户 1.2:修改用户密码 1.3:用户切换与注销 1.4:删除用户 1.5:查询用户信息 1.6:查看当前登录用户 1.7:查看有哪些用户 2:用户组指令 2 ...
- 给DataTable添加额外字段
//dt为DataTable dt.Columns.Add("字段名");//创建字段 //给新增字段赋值 foreach(DataRow item in dt.Rows) { i ...
- Codeforces 1254B1 - Send Boxes to Alice (Easy Version)
题意 有\(n(1\leq n\leq 10^5)\)个盒子,每个盒子有\(a_i(0\leq a_i \leq 1)\)个糖果,你每一次可以将第\(i\)个盒子里的糖果放到第\(i-1\)或\(i+ ...
- [Maven] maven插件系列之maven-shade-plugin
[Maven] maven插件系列之maven-shade-plugin 1 插件简述/Plugin Overview 1.1 定义与目的/Definition & Goals Officia ...
- Solution -「SP 106」BINSTIRL
Description Link. 求 \(\begin{Bmatrix}n \\ m\end{Bmatrix}\bmod2\) Solution 求 \[\begin{aligned} \begin ...