【技术交流】SpringCloud项目接入华为云微服务引擎CSE(二)
目录
1. 业务架构说明
2. 开发环境
3. 本地CSE开发环境搭建
3.1. 下载本地CSE
3.2. 解压,双击cse.exe
3.3. 登录CSE控制台
4. 接入前准备
4.1. 下载实验工程源码,使用IDEA打开
4.2. IDE 配置
4.3. Maven配置
5. 服务端CSE接入
5.1. 主pom修改
5.2. dtse-feign-client接入
5.3. dtse-obs-storage接入
5.4. dtse_system接入
5.5. dtse-zuuL-gateway网关接入
6. 前端服务接入
7. 其他接入中问题记录
1. 业务架构说明
项目Gitee地址
后端 https://gitee.com/caichunfu/dtse-practice-microservice
前端 https://gitee.com/HuaweiCloudDeveloper/dtse-practice-frontEnd/tree/dev
CSE改造前:
• 微服务包含4个微服务模块:zuul-gateway模块、Eureka注册中心、dtse-system模块、obs-storage模块;其中dtse-system模块、obs-storage模块是业务模块。
• 用户发送请求,微服务网关(zuul-gateway) 过滤器根据请求URI,路由和负载均衡请求到不同服务;同时利用JWT进行token校验请求的合法性。
• Eureka注册中心管理zuul-gateway、dtse-system、obs-storage微服务状态;
• dtse-system与obs-storage之间通过feign进行内部接口调用
改造技术路径
• 引入使用spring-cloud-huawei
• 使用华为云CSE服务替换Eureka注册中心的功能
• 使用Spring Cloud Gateway替换zuul网关
基线版本选择
查看 spring-cloud-huawei官网地址:
https://github.com/huaweicloud/spring-cloud-huawei
通过实践master分支与openFeign存在兼容问题,所以本次实践以Hoxton为基线版本,Hoxten与openFeign不存在兼容性问题
由于Spring Cloud Huawei与zuul调试中发现有兼容问题,所以将网关替换成Spring Cloud Gateway
2. 开发环境
JDK |
Openjdk 1.8.0_312 |
Maven |
3.6.3 |
IDEA |
2021.2.2 |
CSE |
Local-CSE-2.1.3-windows-amd64.zip |
spring-boot |
2.3.5.RELEASE |
spring-cloud |
Hoxton.SR9 |
spring-cloud-huawei |
1.8.0-Hoxton |
3. 本地CSE开发环境搭建
3.1. 下载本地CSE
https://cse-bucket.obs.cn-north-1.myhuaweicloud.com/LocalCSE/Local-CSE-2.1.3-windows-amd64.zip
3.2. 解压,双击cse.exe
3.3. 登录CSE控制台
4. 接入前准备
4.1. 下载实验工程源码,使用IDEA打开
源码地址 https://gitee.com/caichunfu/dtse-practice-microservice
4.2. IDE 配置
4.3. Maven配置
使用华为云Maven
5. 服务端CSE接入改造
5.1. 主pom改造
5.1.1. 主pom引入依赖
5.1.2. 使用CSE做为注册中心,删除相关模块和依赖
a、删除eureka-server
b、引入华为spring cloud
` <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>
<spring-cloud-huawei.version>1.8.0-Hoxton</spring-cloud-huawei.version>
</properties>`
<!-- configure user spring cloud / spring boot versions -->
<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>
<!-- 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>
5.2. dtse-feign-client接入
5.2.1. 引入openfeign版本
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.8.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
<version>3.0.3</version>
</dependency>
5.3. dtse-obs-storage接入
5.3.1. Pom文件处理
5.3.1.1. 删除zuul依赖
删除spring-cloud-starter-netflix-zuul,增加spring-cloud-starter-netflix-ribbon
<!--wmh add-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.0.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>ribbon-transport</artifactId>
<groupId>com.netflix.ribbon</groupId>
</exclusion>
<exclusion>
<artifactId>rxnetty</artifactId>
<groupId>io.reactivex</groupId>
</exclusion>
</exclusions>
<optional>true</optional>
</dependency>
<!-- wmh delete
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency> -->
5.3.2. 引入CSE配置
5.3.3. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题
出现这种问题是因为启动类找不到(扫描)其他类的路径,处理方法有多种,我这边使用的是方法二
方法一:把启动类放在其他类文件包的同一级,而不要放在上一级
方法二:在启动类的标签中加入启动扫描的路径如下:
方法三: new个IClientConfig类,不过需要初始化,不然会出现空指针
5.3.3.1. 方法二指定扫描路径:
SpringBootApplication指定扫描路径
@SpringBootApplication(scanBasePackages = {"com.huaweicloud.controller","com.huaweicloud.service","com.huaweicloud.cnmons","com.huaweicloud.persistent"})
@EnableFeignClients
@EnableDiscoveryClient
public class OBSStorageMain {
public static void main(String[] args) {
SpringApplication.run(OBSStorageMain.class, args);
}
}
5.3.3.2. 方法三增加config类:
IClientConfig 类,重点来了,就是这个类,如果不自己定义(openFeign 是可以自定义这个类的,然后自己初始化),那么就千万不要自己去创建一个 bean 出来,然后自己加上注解定义成配置类如下:
@Configuration
public class IClientConfig {
@Bean
public DefaultClientConfigImpl iClientConfig(){
return new DefaultClientConfigImpl();
}
}
这玩意千万不要在程序里自己创建出来,可能很多初学者不是很懂,一开始有配置了这个,结果又只是单纯的 return 了一个没有任何属性的 DefaultClientConfigImpl 对象,然后 openFeign 就会使用你创建的这个对象,结果去初始化的时候,就会在源码里面报空指针异常,把这玩意去掉,基本就可以了,如果要自己定义,那记得把里面该有的属性都要初始化值。
5.4. Dtse_system接入
5.4.1. Pom文件处理
删除eureka client,引入华为service engine
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>spring-cloud-starter-huawei-service-engine</artifactId>
</dependency>
删除netflix-hystrix
<!--
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>-->
5.4.2. 引入CSE配置
5.4.3. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题
package com.huaweicloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication(scanBasePackages = {"com.huaweicloud.controller","com.huaweicloud.cnmons","com.huaweicloud.service","com.huaweicloud.persistent"})
@EnableFeignClients //开启feign客户端调用支持
public class SystemMain {
public static void main(String[] args) {
SpringApplication.run(SystemMain.class, args);
}
}
5.5. Dtse-zuuL-gateway网关接入
使用spring cloud huawei与zuul有兼容性问题,所以切换到Spring Cloud Gateway
5.5.1. Pom文件处理
spring-boot-starter-web排除spring-webmvc包,删除spring-cloud-starter-netflix-zuul包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</exclusion>
</exclusions>
</dependency>
删除eureka-client包
<!--
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>-->
引入spring-cloud-starter-gateway和huawei-service-engine-gateway
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>spring-cloud-starter-huawei-service-engine-gateway</artifactId>
</dependency>
5.5.2. 引入CSE配置
修改网关配置
5.5.3. 修改网关全局过滤器
package com.huaweicloud.filter;
import com.huaweicloud.cnmons.outhUtils.JwtUtil;
import com.huaweicloud.cnmons.response.ResultCode;
import com.huaweicloud.config.URIFilter;
import io.jsonwebtoken.Claims;
import org.apache.servicecomb.foundation.common.utils.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.lang.annotation.Annotation;
@Component
public class RouteConfiguration implements GlobalFilter, Ordered {
@Autowired
JwtUtil jwtUtil;
@Autowired
URIFilter uriFilter;
private String writeJson(Object o) {
try {
return JsonUtils.writeValueAsString(o);
} catch (Exception ee) {
ee.printStackTrace();
}
return null;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("access filter......");
ServerHttpRequest request = exchange.getRequest();
RequestPath path = request.getPath();
System.out.println("收到请求路经:request.getPath() = " + path.value());
// 2、登陆请求放行
if(path.value().contains(uriFilter.getLoginuri().get(0))){
System.out.println("登陆请求路经:request.getPath() = " + path.value());
return chain.filter(exchange);
}
//3、非登陆请求用户权限校验
String authorization = request.getHeaders().getFirst("Authorization");
if (!StringUtils.isEmpty((authorization))) {
System.out.println("非登陆请求路径:request.getPath() = " + path.value());
//2、获取请求头中Token信息
String token = authorization.replace("Bearer", "");
//3、Token校验
Claims claims = jwtUtil.parseToken(token) ;
//4、获取用户id,并将用户id传送到后端
if (claims == null) {
try {
throw new Exception(String.valueOf(ResultCode.UNAUTHENTICATED));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
String id = claims.getId();
//5、添加用户请求头
request.mutate().header("userId",id).build();
return chain.filter(exchange);
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
5.5.4. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题
package com.huaweicloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class},scanBasePackages = {"com.huaweicloud.config","com.huaweicloud.filter","com.huaweicloud.cnmons"})
@EnableDiscoveryClient
public class SpringCloudGatewayMain {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringCloudGatewayMain.class, args);
}
}
6. 前端服务接入
修改vue.config.js,配置服务网关服务的端口
修改login.Vue,通过网关经过systemmain统一接入,所以修改登录url
修改图片上传接口,和获取用户信息接口
7. 其他接入中问题记录
7.1. 方便openFeign调试,openFeign调试,增加Feign日志类
config 增加类FeignConfiguration
package com.huaweicloud.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfiguration {
/**
* 日志级别
*
* @return
*/
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
7.2. Idea 编译报错:Ambiguous method call. Both...
IDEA Settings... > Plugins > 搜索已安装的插件Hrisey Plugins > 禁用该插件
7.3. gateway报错org. springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type 'org.springframework.http.codec.ServerCodec Configurer' that could not be found
spring-cloud-starter-gateway依赖与mvc是不兼容的,如果要引用spring-boot-starter-web需要把mvc排除
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</exclusion>
</exclusions>
</dependency>
7.4. OpenFeign调用报错com.netflix.client.ClientException: Load balancer does not have available server for client: DTSE-OBS-STORAGE
yml 文件里面的服务名,要和 @FeignClient(value = "xxx") 里面的 xxx 一样,切记别弄错,大小写也要一致
- 点赞
- 收藏
- 关注作者
评论(0)