【技术交流】SpringCloud项目接入华为云微服务引擎CSE(二)

HuaweiCloudDeveloper 发表于 2022/01/28 17:09:19 2022/01/28
【摘要】 本项目是将单体项目改造为微服务架构,并将该微服务架构项目改造成支持华为云CSE微服务引擎项目,项目过程中,让您能够熟悉微服务开发模式以及关键组件、华为云servicestage平台,将基于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控制台

    http://127.0.0.1:30103

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.commons","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.commons","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-gatewayhuawei-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.commons.outhUtils.JwtUtil;
import com.huaweicloud.commons.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.commons"})
@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 一样,切记别弄错,大小写也要一致


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。