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
随机推荐
- 微服务集成RabbitMq保姆级教程
本文通过简单的示例代码和说明,让读者能够了解微服务如何集成RabbitMq 之前的教程 https://www.cnblogs.com/leafstar/p/17641358.html 在这里我将介绍 ...
- Kafka-基础
1. 简介 Kafka(Apache Kafka) 是一种分布式流数据平台,最初由LinkedIn开发,并于后来捐赠给Apache软件基金会,成为了一个Apache顶级项目.它被设计用于处理大规模.实 ...
- iOS添加图片
添加一个按钮 将图片添加到
- 代码检视的新姿势!在IDEA中得到沉浸式Code Review新体验
大家好,好久不见,又见面了. 在消失的这段时间里,我做了件大事,见证了儿子的出生并陪伴其一天天的成长.停止更文的200多天里,还能得到小伙伴们持续的支持,让我备受鼓励.对一个技术人员而言,分享技术观点 ...
- zabbix 警报推送至企业微信(图文版)
新增Python脚本 # encoding: utf-8 import sys import requests import json import os import time import re ...
- open3d -- voxel_down_sample
官网文档 parameter: Input: open3d.geometry.Pointcloud点云类 voxel_size: 体素单位长度 Return: 处理后的点云类 Description: ...
- 研发提速:nacos+openfeign环境下的本地链接服务
项目研发过程中,经常会遇到与测试人员工作重叠的情况,十分影响效率. 做了一个修改,可以在本地环境启动项目后和测试环境交互,并且不影响测试环境,理论上也可以用于线上环境的异常的快速处理. 准备事项如下: ...
- ModuleNotFoundError: No module named 'qrcode'
W File "/usr/lib/python3/dist-packages/pip/_internal/resolution/resolvelib/candidates.py", ...
- python加解密小工具
1.地址 https://github.com/Doneone/RSA_GUI 2.用法 python3 rsa_gui.py 创建密钥对 3.思考 为什么要写rsa小工具呐,因为单纯想实现一个简单的 ...
- spring-boot集成hikari多数据源
maven依赖 <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</ ...