description |
---|
基于Spring Cloud gateway & Springmvc服务合并 |
当前项目中,服务拆分的粒度太小,每个服务都需要单独启动一个jvm进程,导致服务器内存不足,因此需要对微服务做合并
合并服务,降低内存使用
服务A:业务服务,和具体业务逻辑相关;url = /serviceA/**, context-path=/serviceA
服务B:通用服务,主要是发送短信,文件上传等功能;url = /serviceB/**, context-path=/serviceB
1、服务A和服务B的subpath没有冲突
2、服务A和服务B的数据库是同一个
3、application.yml只有基础的内容,大部分配置都在nacos上
因此,可以考虑直接合并
具体思路是,服务B变成一个通用java jar,由服务A引入
1、原有的路由规则需要调整
2、serviceB的url将会从/serviceB/**变成/serviceB/**
- 删除application.yml
- 删除Application类(包含main方法的类)
- 删除springboot maven plugin
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
<!--指定打包时候将依赖一起打包-->
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
- 添加普通打包插件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
<skip>true</skip>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
- 修改nacos配置,去掉数据库等和serviceA重复的内容
- 添加serviceB jar依赖
- componentScan添加serviceB 根路径 (@ComponentScan)
- mapper添加serviceB mapper根路径 (@MapperScan)
- application.yml 引入 serviceB的nacos配置
spring:
# ...
config:
import:
- optional:nacos:serviceB.yml?group=DEFAULT_GROUP&refreshEnabled=true
首先在serviceB中添加拦截器,将/serviceA/serviceB/xxx 转发到/serviceB/xxx
@Slf4j
public class ForwardInterceptor implements HandlerInterceptor {
private String prefix;
public ForwardInterceptor(String prefix) {
this.prefix = prefix;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
// path修正为去掉context-path之后的真实uri
String newURI = requestURI.replaceFirst(prefix + "/serviceB", "");
log.debug("ForwardInterceptor.preHandle, prefix={}, requestURI: {}, newURI={}", prefix, request.getRequestURI(), newURI);
// 转发
request.getRequestDispatcher(newURI).forward(request, response);
return false; // 转发完请求就结束了,这里一定要返回false
}
}
@Slf4j
@Configuration
public class InfInterceptorConfig implements WebMvcConfigurer {
@Value("${spring.application.name}")
private String application;
@Value("${server.servlet.context-path}")
private String contextPath;
public static final String STATIC_CONTENT = "/static/file/**";
private static final String ORIGIN_APPLICATION = "serviceB";
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 这里做兼容,如果serviceB回退为spring boot fat jar时,不做任何处理
if (ORIGIN_APPLICATION.equalsIgnoreCase(application)) {
return;
}
log.info("forward interceptor add, application={}, context-path={}", application, contextPath);
// 配置需要的转发路径
registry.addInterceptor(new ForwardInterceptor(contextPath))
.addPathPatterns("/serviceB/**");
}
}
spring:
gateway:
routes:
- id: serviceA
uri: lb://serviceA # serviceA
predicates:
- Path=/api/serviceA/**
filters:
- StripPrefix=1
- id: serviceB
uri: lb://serviceA # 注意这里需要改成serviceB
predicates:
- Path=/api/serviceB/**
filters:
# 这里需要做一个url rewrite
- RewritePath=/api/serviceB/?(?<segment>.*), /api/ticket/serviceB/$\{segment}
- StripPrefix=1
@FeignClient(name = "serviceA", contextId = "serviceB", path = "/serviceA", fallbackFactory = InfrastructureFeignClientFallbackFactory.class)
public interface ServiceBFeignClient {
// ...
}
- name:服务提供方id,这里需要改成serviceA
- contextId:beanId,防止冲突,还是配置下比较保险
- path:因为url都变成为/serviceA/serviceB/**了,所以这里需要加上/serviceA统一前缀
1、升级serviceA
2、serviceB调用方依次升级,观察
3、gateway转发规则更新,重启,观察
4、无流量后下掉serviceB