在线教育项目第十天

本文详细介绍了如何使用Spring Cloud构建微服务,包括服务注册与发现(Nacos)、服务调用(Feign)以及熔断器(Hystrix)的配置和应用。在实际操作中,通过微服务实现了删除课程时同时删除视频的功能,并针对可能出现的问题进行了讨论和解决方案的提供。
摘要由CSDN通过智能技术生成

一、微服务

概念
    本项目中父工程中的不同模块占用不同的端口号
    微服务是一种架构风格/方式
    一个项目拆分为多个服务,每个服务独立运行,每个服务占用独立进程,可以将每个服务单独部署在不同的服务器上
优点
    程序扩展方便,部署方便,代码量减少,容易定位问题
    每个模块可以使用不得存储方式,有的使用redis,有的使用MySQL
    每个模块可以使用不同的语言开发
如果系统提供的业务是偏底层的,比如操作系统内核、存储系统、网络系统、数据库系统等,功能之间紧密配合,不适合使用微服务
常用框架
    Spring Cloud
    Dubbo
    Dropwizard

二、Spring Cloud

一系列框架的集合,使用这些框架可以实现微服务
使用要依赖于Springboot
Springboot是快速构建Spring的脚手架,SpringCloud是一系列框架的总称,要使用SpringCloud需要依赖于Springboot才能实现里面的功能
组件
    服务发现 Netflix Eureka (Nacos) 注册中心
    服务调用 Netflix Feign
    熔断器 Netflix Hystrix
    服务网关 Spring Cloud GateWay
    分布式配置 Spring Cloud Config (Nacos)
    消息总线 Spring Cloud Bus (Nacos)
注意和Springboot的版本对应,参考https://start.spring.io/actuator/info ,这里springboot2.4.1对应springcloud2020.0.1
版本后缀
    SNAPSHOT 快照版本 随时可能修改
    M 里程碑版本 实现了预定的目标
    SR 正式版本
    GA 稳定版本

三、使用微服务实现删除小节的同时删除视频

1、注册中心

edu模块中删除小节的方法调用vod模块中的删除视频方法
不能直接在edu中引入vod的依赖,这会造成两个模块之间产生关联
在注册中心Nacos中注册要互相调用的两个模块,注册之后就可以实现互相调用
常用注册中心
    Eureka
    Zookeeper
    Consul
    Nacos 原生 go开发
Eureka是springcloud中原始的注册中心,但其在2.0遇到性能瓶颈,停止维护,所以现在通常使用阿里巴巴提供的Nacos

2、Nacos

可以作为注册中心 配置中心 消息总线
流程
    Nacos作为注册中心,vod作为Provider,edu作为Customer
    Provider和Customer在注册中心根据ip,端口号进行注册
    CUstomer在注册中心得到Provider的ip,端口号,然后直接访问Provider,调用对应方法,返回结果
安装
    https://github.com/alibaba/nacos/release
    不要选择beta版本,其用于公测
    解压
使用
    打开bin目录,双击startup.cmd启动
    访问Nacos http://localhost:8848/nacos 用户名和密码都是nacos
    服务管理-服务列表显示注册的服务

3、将service_edu注册到Nacos中

在service模块中引入依赖
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
在要注册的模块service_edu的application.properties文件中进行配置
    # nacos服务地址
    spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
在要注册的模块service_edu的启动类上加上注解@EnableDiscoveryClient,表示进行注册

4、将service_vod注册到Nacos中

在要注册的模块service_vod的application.properties文件中进行配置
    # nacos服务地址
    spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
在要注册的模块service_vod的启动类上加上注解@EnableDiscoveryClient,表示进行注册

5、测试

启动service_edu和service_vod
访问Nacos,就可以在服务列表中看到service_edu和service_vod了,具体的名称是application.properties中配置的服务名,注意不要加_
问题:启动报错db.num is null
解决:默认的启动里面是配置的集群版的,本机运行的话要改成单机版即可
    打开解压后的文件夹/bin/startup.cmd 右键编辑,在set MODE="cluster"前面加上rem注释,然后加上set MODE="standalone" 参考https://www.freesion.com/article/87611162023/
双击shutdown.cmd停止nacos

6、使用Feign组件实现服务调用

Netflix开发的
service中引入依赖
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
在调用端service_edu的启动类上加上注解@EnableFeignClients
调用端service_edu创建一个接口VodClient
    加上注解@Component交给spring管理
    加上注解指定要调用的服务名
        @FeignClient("service-vod")
    定义要调用的方法的路径 url要写全,加上controller的url
        @DeleteMapping("/eduvod/video/deleteVideoById/{id}")
        public R deleteVideoById(@PathVariable("id") String id);
        参数中的@PathVariable一定要指定参数的名称@PathVariable("id")
EduVideoController
    注入VodClient
        @Autowired
        private VodClient vodClient;
    在删除小节的方法findVideoById中调用vod的方法删除视频
        @DeleteMapping("deleteVideoById/{id}")
        public R deleteVideoById(@PathVariable String id) {
            //根据小节id得到视频id,先得到对应的小节对象
            EduVideo video = eduVideoService.getById(id);
            String videoSourceId = video.getVideoSourceId();
            //调用vod的删除视频的方法
            if (!StringUtils.isEmpty(videoSourceId)) {
                vodClient.deleteVideoById(videoSourceId);
            }
            //删除小节
            boolean flag = eduVideoService.removeById(id);
            return flag ? R.ok() : R.error();
        }
    实现原理
       调用VodClient中的方法时会根据指定的服务名去远程调用service_vod中的方法,相当于创建实现类调用

7、问题

启动edu时控制台报错:No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?
    加上了依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
    之后还是在删除小节的时候报错:
        Receiver class org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient does not define or
    之后将父工程pom文件中的springboot和springcloud的版本降低了之后就可以了,上面的loadbalancer依赖也去掉
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.1.RELEASE</version>
            <relativePath/>
        </parent>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        参考:https://blog.csdn.net/padawan75/article/details/112616053

8、将service_oss注册到Ncaos中

否则启动时会报错提示服务不可用,因为在service中引入了依赖,会默认找注册中心的配置
在要注册的模块service_oss的application.properties文件中进行配置
    # nacos服务地址
    spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
在要注册的模块service_oss的启动类上加上注解@EnableDiscoveryClient,表示进行注册

四、删除课程的同时删除视频

一个课程对应多个章节,一个章节对应多个小节,每个小节对应一个视频,所以删除一个课程需要删除多个视频
删除多个视频可以循环调用vod中根据视频id删除视频的方法,也可以再创建一个删除多个视频的方法

1、VodController

创建删除多个视频的方法,使用多个视频id的list集合作为参数,调用service的方法
    @DeleteMapping("deleteMultiVideos")
    public R deleteMultiVideos(@RequestParam("videoIdList") List videoIdList) {
        vodService.deleteMultiVideos(videoIdList);
        return R.ok();
    }

2、VodServiceImpl

创建删除多个视频的方法
    使用org.apache.commons.lang.StringUtils中的join方法将list集合转换为以逗号隔开的参数形式
        @Override
        public void deleteMultiVideos(List<String> videoIdList) {
            try {
                //创建DefaultAcsClient对象
                DefaultAcsClient client = InitClient.initVodClient(ConstantVodUtils.KEY_ID, ConstantVodUtils.KEY_SECRET);
                //创建DeleteVideoRequest对象
                DeleteVideoRequest request = new DeleteVideoRequest();
                //设置request的参数
                String videoIds = StringUtils.join(videoIdList, ",");
                request.setVideoIds(videoIds);
                //调用方法删除视频
                client.getAcsResponse(request);
            } catch (ClientException e) {
                e.printStackTrace();
                throw new OrangeException(20001, "删除视频失败");
            }
        }

3、VodClient

定义vod中删除多个视频的方法,url写全
    @DeleteMapping("/eduvod/video/deleteMultiVideos")
    public R deleteMultiVideos(@RequestParam("videoIdList") List<String> videoIdList);
    注意List加上泛型

4、EduCourseServiceImpl

注入VodClient
    @Autowired
    private VodClient vodClient;
在根据课程id删除小节的方法removeVideoByCourseId中调用vod中删除多个视频的方法
    @Override
    public void removeVideoByCourseId(String courseId) {
        QueryWrapper<EduVideo> wrapper = new QueryWrapper<>();
        wrapper.eq("course_id", courseId);
        //根据课程id查询出课程中所有的视频id
        List<EduVideo> eduVideos = baseMapper.selectList(wrapper);
        List<String> videoIdList = new ArrayList<>();
        for (EduVideo eduVideo : eduVideos) {
            String videoSourceId = eduVideo.getVideoSourceId();
            if (!StringUtils.isEmpty(videoSourceId)) {
                videoIdList.add(videoSourceId);
            }
        }
        //删除视频
        if (videoIdList.size() > 0) {
            vodClient.deleteMultiVideos(videoIdList);
        }
        //删除小节
        baseMapper.delete(wrapper);
    }

五、熔断器Hystrix

springcloud在接口调用上大致经过以下几个组件的配合

Feign-Hystrix-Ribbon-Http Client(apache http components 或 Okhttp)
接口化请求调用
    指定调用的服务名和接口地址
Feign服务发现
    根据服务名和接口地址进行调用
Hystrix
    调用服务时如果调用不到,比如服务挂了,就切断调用连接,称为熔断机制
Ribbon
    将请求平均分担到要调用的服务的集群的不同服务器中
Http Client
    根据ip 端口号访问要调用的服务,执行方法

Hystrix

分布式部署
    将项目的不同服务部署到不同的服务器上
容错
    要调用的服务宕机了,熔断器断开连接,使其不能被访问
延迟
    设置请求时间在多长时间内都算正确

使用

1、service加上依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2、service_edu的application.properties加上配置
# 开启熔断机制
feign.hystrix.enabled=true
3、创建VodClient的实现类VodClientImpl
加上注解@Component
重写方法,这里的方法只有在调用服务失败时才会执行
    @Override
    public R deleteVideoById(String id) {
        return R.error().message("删除视频出错");
    }
    @Override
    public R deleteMultiVideos(List<String> videoIdList) {
        return R.error().message("删除多个视频出错");
    }
4、在VodClient接口上修改注解
fallback=接口实现类,表示出错后执行实现类的方法
@FeignClient(name = "service-vod", fallback = VodClientImpl.class)
5、在EduVideoController的deleteVideoById方法中加上对删除返回值的判断
if (!StringUtils.isEmpty(videoSourceId)) {
    R r = vodClient.deleteVideoById(videoSourceId);
    if (r.getCode() == 20001) {
        throw new OrangeException(20001, "删除视频失败,熔断器执行");
    }
}
6、测试
启动vod,debug启动edu
在String videoSourceId = video.getVideoSourceId();前加断点
添加课程,添加章节,添加小节,添加视频
停止vod
点击删除小节,断点停在了刚才的位置
点击stop over按钮/F8 向下执行
执行到判断语句,返回删除视频出错
向下执行,抛出异常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值