这篇文章主要基于两个不同服务之间应该如何实现相互调用
背景:随着微服务架构的逐渐成熟,我们习惯把大型的互联网项目拆分成不同的模块,再把这些不同的模块部署到不同的服务器上,那我们应该如何构建这多个模块(服务)之间的关系呢?
问题:当我们项目中的某个课程模块需要调用用户的登录模块,该如何处理?
[1] 可以直接使用dependency去引入依赖,调用相关的方法(可这违背了微服务的理念,也不能很好的解耦;)
[2] 两个模块都把自己的信息都注册到一个注册中心中,服务调用方可以通过这个中心去调用服务供给方提供的方法。
(什么是注册中心呢?)
[1] 基本概念
Nacos 是阿里巴巴推出来的一个新开源项目,Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
[2] 常见的注册中心
Eureka(原生,2.0遇到性能瓶颈,停止维护)
Zookeeper(支持,专业的独立产品。例如:dubbo)
Consul(原生,GO语言开发)
Nacos
相对于Spring Could Eureka来说,Nacos更强大,Nacos = Spring Cloud Eureka + Spring Cloud Config;
Nacos可以与Spring, Spring Boot, Spring Could集成,并能代替 Spring Cloud Eureka, Spring Cloud Config
通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-discovery 实现服务的注册与发现。
【3】Nacos支持所有主流的服务发现、配置和管理
Nacos主要提供以下四大功能:
(1)服务发现和服务健康监测
(2)动态配置服务
(3)动态DNS服务
(4)服务及其元数据管理
下载地址:https://github.com/alibaba/nacos/releases
下载版本:nacos-server-1.1.4.tar.gz或nacos-server-1.1.4.zip,解压任意目录即可
[1] 解压后在 bin目录下找到对应的脚本便可启动
[2] 访问:http://localhost:8848/nacos
用户名密码:nacos/nacos
这里我们以刚才的项目场景为实例(即课程服务要去调用用户登录服务;这里先介绍注册的流程,后面介绍调用的流程)
[1] 在pom.xml中引入依赖
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
<version>2.2.1.RELEASEversion>
dependency>
[2] 在两个服务的application.properties中添加服务配置信息(因此都要进行注册)
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
[3] 在两个服务的启动类上添加注解 @EnableDiscoveryClient(表示注册)
[4] 这时我们查看注册中心,发现服务列表多了两个服务
上面所讲的是关于服务的一种简单注册,但对于业务上的调用我们还没有做相关实现。这里我们需要用到SpringCould的另一个组件Feign,它主要就是用于服务的调用。
[1] Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。
[2] Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
[3] Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
[4] Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。
[5] Spring Cloud Feign帮助我们定义和实现依赖服务接口的定义。在Spring Cloud feign的实现下,只需要创建一个接口并用注解方式配置它,即可完成服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发.
对于Fegin的简单理解,我们放到注册中心上的服务,总是会有服务的调用方和服务的供给方(即我们平时所说的消费者和生产者). 对于服务调用相关的主体代码应该在消费者上编写。
(对于我们的业务:课程模块需要调用用户中心模块,那么课程模块就是消费者,用户中心模块就是生产者;那么相关代码应该在课程模块上编写)
[1] 在课程模块的pom.xml中引入依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
<version>2.2.2.RELEASEversion>
dependency>
[2] 在启动类上添加注解 @EnableFeignClients
[3] 创建调用的接口和实现类
注意点:接口中的方法名和参数要和生产者的方法和参数一致。
如:我要调用的是用户中心模块的根据token获取用户信息的方法
那我在消费者方的接口应该这么定义:
(1)其中@FeignClient注解用于指定从哪个服务中调用功能 ,名称与被调用的服务名保持一致;(即我们application.properties中所配置的服务名), fallback表示你要编写的实现类(该实现类只有调用失败才会执行,这个类也可以省略)
(2) GetMapping上要写上调用方的全接口地址
(3) @Component注解防止,在其他位置注入CodClient时idea报错
完整代码:
package com.gs.eduService.client;
import com.gs.commonutils.R;
import com.gs.eduService.entity.UcenterMember;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import javax.servlet.http.HttpServletRequest;
@Component
@FeignClient(name="service-ucenter",fallback=UcenterClientImpl.class)
public interface UcenterClient {
//3.根据token获取用户信息
@GetMapping("api/ucenter/wx/getUcenterMember/{memberId}")
public UcenterMember getMemberById(@PathVariable String memberId);
}
UcenterClientImpl.class (这个类非必须)
[4] 在需要调用的地方上注入UcenterClient ,并调用相关方法