老鸟飞过 ,只做学习使用,欢迎交流
1.什么是Nacos
在《Spring Cloud 极简入门》中我们学习了netflix 的 Eureka 组件作为微服务的服务发现。Nacos和Eureka有着相同的能力,甚至更为强大,作为Dubbo 生态系统中重要的注册中心实现。官方对它有如下定义:
Nacos致力于帮助您发现,配置和管理微服务。它提供了一组简单有用的功能,使您能够实现动态服务发现,服务配置,服务元数据和流量管理。
Nacos使构建,交付和管理微服务平台变得更容易,更快捷。它是通过微服务或云原生方法支持以服务为中心的现代应用程序体系结构的基础架构。
这里我们看到Nacos不仅是服务发现组件,同时也是一个配置管理组件,也就是说它不仅可以用来取代Eureak作为注册中心, 也可以用来取代Spring Cloud Config 做配置统一管理。本篇文章意在探讨Nacos的服务注册与发现功能。
2.Nacos服务安装
官方提供了Nacos的服务端供我们下载使用,我们启动Nacos后将我们的微服务注册进入Nacos即可。
下载地址:https://github.com/alibaba/nacos/releases
启动Nacos:解压后, windows执行bin目录下的startup命令 ,linux 执行 sh startup.sh -m standalone
访问Nacos,端口8848:http://127.0.0.1:8848/nacos/index.html ,用户名和密码都是:nacos
登录成功之后:
3.演示案例分析
3.1.服务调用流程
我们这里要演示的案例是两个服务的通信,用户服务(user-server)作为服务提供者需要编写接口返回User实体对象,订单服务(order-server)作为消费者需要调用用户服务获取User实体对象,浏览器调用订单服务,订单服务调用用户服务或到User实体后返回给容器,用户和订单都注册到Nacos中,如下:
注意:这里的订单服务和用户服务都用到了User实体,所以为了让User实体共用,我们为User实体抽取了一个公共的user-common模块,用户服务和订单服务都去依赖这个模块即可使用User实体。
3.2.项目结构搭建
我们根据上面的图例来搭建项目环境,这里使用多模块方式演示,搭建父工程,提供者服务,消费者服务,以及公共的user-common模块,结构如下:
springcloudalibaba-parent
pom.xml
springcloudalibaba-user-common //公共的user实体,服务调用传输对象
springcloudalibaba-order-server-1020 //消费者服务
springcloudalibaba-user-server-1010 //提供者服务
父工程搭建
搭建父工程springcloudalibaba-parent并管理相关依赖,Spring boot版本为2.1.3.RELEASE,Spring Cloud 版本为Greenwich.SR1,Alibaba版本为2.1.0.RELEASE ,父工程的pom如下:
<!--公共的一些配置-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
<alibaba.version>2.1.0.RELEASE</alibaba.version>
<spring-boot.version>2.1.13.RELEASE</spring-boot.version>
</properties>
<!--1.管理SpringBoot的依赖-->
<parent>
<groupId> org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${alibaba.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>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
4.提供者服务注册到Nacos
4.1.导入依赖
修改springcloudalibaba-user-server-1010导入服务发现依赖
<dependency>
<groupId>com.alibaba.cloud </groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--加入WEB依赖是为了方便后面写Controller-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
4.2.主配置类
创建配置类加上@EnableDiscoveryClient注解开启服务发现功能,代码如下
//服务注册与发现
@SpringBootApplication
@EnableDiscoveryClient
public class UserServerApplication1010 {
public static void main(String[] args) {
SpringApplication.run(UserServerApplication1010.class) ;
}
}
4.3.配置文件
配置文件主要配置端口,服务名,已经nacos注册中心地址
server:
port: 1010
spring:
application:
name: user-server
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #注册中心地址
4.4.启动测试
启动服务提供者,观察Nacos服务列表 , user-server已经注册进去了
5.服务消费者注册到Nacos
消费者服务(springcloudalibaba-order-server-1020)的所有流程和提供者服务一样,这里不再赘述,消费者的端口是 1020 ,服务名是order-server 。
分别启动2个工程,待工程启动成功之后,在访问localhost:8848,可以发现user-server和order-server,均已经向nacos-server注册
6.使用Ribbon进行服务通信
6.1.公共user模块
给springcloudalibaba-user-common添加user实体类
public class User {
private Long id;
private String name;
private String intro;
public User() {
}
public User(Long id, String name, String intro) {
this.id = id;
this.name = name;
this.intro = intro;
}
//getter,setter...
6.2.服务提供者
修改springcloudalibaba-user-server-1010 的pom文件,依赖springcloudalibaba-user-common模块
<dependency>
<groupId>org.example</groupId>
<artifactId>springcloudalibaba-user-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
修改springcloudalibaba-user-server-1010 编写controller ,这个是向消费者暴露的访问接口。
@RestController
public class UserController {
@GetMapping("/user/{id}")
public User getById(@PathVariable Long id){
return new User(id,"zs:"+id, "我是zs");
}
}
6.3.消费者服务
修改springcloudalibaba-order-server-1020,修改pom导入user-common依赖
<dependency>
<groupId>org.example</groupId>
<artifactId>springcloudalibaba-user-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
修改springcloudalibaba-order-server-1020 ,在配置类定义RestTemplate,使用@LoadBalanced开启负载均衡,Nacos默认整合了Ribbon。
不知道Ribbon?点我
//服务注册与发现
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServerApplication1020 {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(OrderServerApplication1020.class) ;
}
}
创建controller,通过RestTemplate向用户服务发起请求
//订单消费者
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/order/{id}")
public User getById(@PathVariable Long id){
String url = "http://user-server/user/"+id;
return restTemplate.getForObject(url,User.class);
}
}
访问测试 : http://localhost:1020/order/3 , 返回从用户拿到的用户信息:
{
"id":3,"name":"zs:3","intro":"我是zs"}
7.使用Feign进行服务通信
上面我们的消费者服务(order-server)通过Ribbon向提供者服务(user-server)发起调用并成功的获取到结果,当然我们也可以使用Feign实现服务的调用,集成方式和以前一模一样。还不知道Feign?点我
7.1.创建支付服务
创建新的工程springcloudalibaba-pay-server-1030 作为第二个消费者服务,同时依赖user-common模块,注册到Nacos,集成Feign和user-server通信,导入依赖如下:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 服务注册与发现-->
<dependency>
<groupId>com.alibaba.cloud </groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>springcloudalibaba-user-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
7.2.主配置类
通过 @EnableFeignClients注解开启Feign。
//服务注册与发现
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients("org.example.feign.client")
public class PayServerApplication1030 {
public static void main(String[] args) {
SpringApplication.run(PayServerApplication1030.class) ;
}
}
7.3.编写Feign接口
该接口作为Feign的客户端接口,用来调用用户服务(user-server)
@FeignClient("user-server")
public interface UserClient {
@GetMapping("/user/{id}")
User getById(@PathVariable Long id);
}
7.4.编写测试Controller
通过 UserClient Feign的客户端接来调用用户服务,获取User并返回。
@RestController
public class PayController {
@Autowired
private UserClient userClient ;
@RequestMapping("/pay/{id}")
public User getById(@PathVariable Long id){
return userClient.getById(id);
}
}
7.5.访问测试
测试调用 :http://localhost:1030/pay/3 , 返回数据如下:
{
"id":3,"name":"zs:3","intro":"我是zs"}
总结:
为什么我们可以在Spring Cloud Alibaba里面无缝兼容 Ribbon和Feign呢,这是因为Spring Cloud Comm包对SpringCloud的一些基本功能做了封装,比如在服务注册与发现、客户端负载均衡等方面都做了很好的抽象,而上层应用方面依赖的都是这些抽象接口,而非针对某个具体中间件的实现。所以,在Spring Cloud中,我们可以很方便的去切换服务治理方面的中间件。