最近有项目需求把现有的单体应用,springboot接入华为的微服务引擎CSE,这里列出我遇到的问题,以及解决方案。
1、华为CSE微服务引擎的POM文件引入
问题:POM文件无法找到对应的华为CSE资源。
方案:指定pom仓库,指定CSE版本号
参考华为自带的镜像源找不到的话,去下面这个指定的镜像源,一定能找到
<properties>
<java.version>1.8</java.version>
<spring-boot.version>2.3.5.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<!-- https://mvnrepository.com/artifact/com.huaweicloud/spring-cloud-starter-huawei-service-engine -->
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>spring-cloud-starter-huawei-service-engine</artifactId>
<version>1.10.1-2021.0.x</version>
</dependency>
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>spring-cloud-huawei-bom</artifactId>
<version>1.8.0-Hoxton</version>
<type>pom</type>
<scope>import</scope>
</dependency>
配置仓库镜像源 huaweicloud
<repositories>
<repository>
<id>huaweicloud</id>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
</repository>
<repository>
<id>central</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<name>aliyun</name>
</repository>
</repositories>
这里只是部分的pom文件,后面会贴上完整的pom文件内容。
2、新增bootstrap.yaml
位置:\src\main\resources
这个配置文件内容如下:
spring:
application:
# 微服务名称,本示例使用固定值(可替换成自己想要的名字),因为微服务名称会被客户端使用,不能轻易变化。
name: basic-consumer
cloud:
servicecomb:
discovery:
# 应用名称,本示例固定值(可替换成自己想要的名字),因为只有应用名称相同的微服务才能够相互发现,不能轻易变化。
appName: basic-application
serviceName: ${spring.application.name}
# 注册中心地址,本示例使用ServiceStage环境变量。建议保留这种配置方式,部署的时候,不用手工修改地址。
address: ${PAAS_CSE_SC_ENDPOINT:http://127.0.0.1:30100}
# 微服务版本号,本示例使用ServiceStage环境变量。建议保留这种配置方式,部署的时候,不用手工修改版本号,防止契约注册失败。
version: ${CAS_INSTANCE_VERSION:0.0.1}
config:
# 配置中心地址,本示例使用ServiceStage环境变量。建议保留这种配置方式,部署的时候,不用手工修改地址。
serverAddr: ${PAAS_CSE_CC_ENDPOINT:http://127.0.0.1:30110}
serverType: kie
server:
#用于区分微服务环境,取值为development、testing、acceptance、production。当配置为development、testing或acceptance时,可以通过批量上传schemas接口新增或者修改已存在的Schema;当配置为production时,则不可以新增或者修改Schema。默认值development。
env: development
3、修改启动类
这里新增一个注解@EnableDiscoveryClient即可
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4、新增/修改项目配置 application.yaml
里面只保留基础配置就行了,业务配置可以直接托管给CSE的配置中心,我只保留了一个端口
server:
port: ${PORT:8080}
5、启动本地的CSE引擎
启动成功如图所示
5、启动本地的springboot
最后打开打开控制台 http://127.0.0.1:30103/
可以看到刚才注册的实例,这是一个消费者,还需要一个服务提供者
6、配置服务提供者(另一套springboot程序)
spring:
application:
# 微服务名称,本示例使用固定值(可替换成自己想要的名字),因为微服务名称会被客户端使用,不能轻易变化。
name: basic-provider
cloud:
servicecomb:
discovery:
# 应用名称,本示例固定值(可替换成自己想要的名字),因为只有应用名称相同的微服务才能够相互发现,不能轻易变化。
appName: basic-application
serviceName: ${spring.application.name}
# 注册中心地址,本示例使用ServiceStage环境变量。建议保留这种配置方式,部署的时候,不用手工修改地址。
address: ${PAAS_CSE_SC_ENDPOINT:http://127.0.0.1:30100}
# 微服务版本号,本示例使用ServiceStage环境变量。建议保留这种配置方式,部署的时候,不用手工修改版本号,防止契约注册失败。
version: ${CAS_INSTANCE_VERSION:0.0.1}
watch: false
healthCheckInterval: 30
config:
# 配置中心地址,本示例使用ServiceStage环境变量。建议保留这种配置方式,部署的时候,不用手工修改地址。
serverAddr: ${PAAS_CSE_CC_ENDPOINT:http://127.0.0.1:30110}
serverType: kie
server:
env: development
定义服务提供者接口
@GetMapping("/ms/8088test")
public String getMs8088test() {
System.out.println("收到请求");
return "this is 8088's test";
}
@GetMapping("/sayHello")
public String sayHello(@RequestParam("name") String name) {
return "Hello this is micro service return :" + name;
}
启动服务,看到控制台服务已经有新增进来。
7、测试
@RestController
@Slf4j
//配置动态刷新
@RefreshScope
public class MicroserviceDemoController {
@Value("${people.name.en}")
private String nameEn;
@Autowired
private ConfigListen configListen;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/configTest")
public String gCodeTest() {
String name = configListen.getName();
return name + nameEn;
}
@GetMapping("/requestTest")
public String gCodeTest2() {
String okapiUrl = "http://basic-provider/v1/sayHello?name=caicaiDog";
HttpHeaders httpHeaders = new HttpHeaders();
ResponseEntity<String> exchange = restTemplate.exchange(okapiUrl, HttpMethod.GET, new HttpEntity<>(null, httpHeaders), String.class);
return exchange.getBody();
}
@GetMapping("/sayHello")
public String sayHello(@RequestParam("name") String name) {
return restTemplate.getForObject("http://basic-provider/v1/sayHello?name={1}", String.class, name);
}
}
说明:configTest这个接口用于测试配置中心的获取,配置中心如下:
访问后得到值,均是配置中心的配置值。
重要说明:这个配置值可以在后台进行更改,代码里面的取值不会发生变化。只有下次重启服务才会获取最新的值。
如果需要实时变化,新增新增@RefreshScope注解到配置类上,这样就可以实现配置实时变化了。
{"code":200,"data":"zhang san,enenenen","message":"ok","status":0}
微服务之间的调用可以采用Feign或者RestTemplate或者你喜欢的其他的HTTP工具,其中RestTemplate的在上面代码中有展示。
Feign调用方式如下:
//定义接口
@FeignClient(value = "basic-provider")
public interface FeignConsumerService {
@GetMapping("/sayHelloFeign")
String sayHelloFeign(@RequestParam("name") String name);
}
//控制器调用
@GetMapping("/sayHelloFeign")
public String sayHelloFeign(@RequestParam("name") String name) {
return feignConsumerService.sayHelloFeign(name);
}
CSE引入进来遇到的坑记录:
1、springboot版本需要升级到2.6.9也支持升级到2.7.x
这个都好说,我只是升级后遇到一些和老代码不兼容的问题,已经处理了。
1、以前的接口全部返回XML格式了
这里需要屏蔽掉CSE引入的包
1、swagger不能正常使用了
这里还是看依赖关系图找到的
打开swagger报错
Unable to render this definition
The provided definition does not specify a valid version field.
Please indicate a valid Swagger or OpenAPI version field. Supported version fields are swagger: “2.0” and those that match openapi: 3.0.n (for example, openapi: 3.0.0).
还以为是swagger的问题,结果不是,最坑的是swagger这个错误太不明显且误导人。
通过排查swagger接口http://localhost:8080/v1/v3/api-docs,发现报错信息如下:
Ambiguous handler methods mapped for ‘/v1/v3/api-docs’: {public org.springframework.http.ResponseEntity springfox.documentation.oas.web.OpenApiControllerWebMvc.getDocumentation(java.lang.String,javax.servlet.http.HttpServletRequest), public java.lang.String org.springdoc.webmvc.api.OpenApiWebMvcResource.openapiJson(javax.servlet.http.HttpServletRequest,java.lang.String,java.util.Locale) throws com.fasterxml.jackson.core.JsonProcessingException}
解决方法:
排除CSE中的swagger
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.9</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 微服务相关配置 -->
<!-- https://mvnrepository.com/artifact/com.huaweicloud/spring-cloud-starter-huawei-service-engine -->
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>spring-cloud-starter-huawei-service-engine</artifactId>
<version>1.10.1-2021.0.x</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
<exclusion>
<groupId>com.huaweicloud</groupId>
<artifactId>spring-cloud-starter-huawei-swagger</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- configure spring cloud huawei version -->
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>spring-cloud-huawei-bom</artifactId>
<version>${spring-cloud-huawei.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 微服务相关配置 结束 -->
到此,所有问题都解决了