中秋佳节,来玩一波 SpringCloudAlibaba 之 Nacos 服务提供与消费实战
中秋佳节当天,人在异乡,无法和家人团聚,既然如此 不如提升一波自己的姿势水平,免得浪费这假期大好光阴。
说道微服务,现在可不流行Netfilx那一套了, 现在都9102年9月了,Spring Cloud Aliabba都已经孵化完毕,再加上Netfilx将他旗下的项目通通打入冷宫,现在在不学习SpringCloudAlibaba体系就赶不上时代的潮流了。 Netfilx那套体系我都搭过demo 写过博客,各种配置啊注意点啊都挺详细的,感兴趣的可以翻我以前的文章。
https://github.com/alibaba/spring-cloud-alibaba 这是 SpringCloudAlibaba 的项目 git。
这篇文章主要是开个SpringCloudAliabba篇的头,正式开始SpringCloudAlibaba的学习。
废话不多说,进入正题。
今天就从微服务最重要的地方开始,当然,也只能从这个地方开始。
那就是服务治理。
在 Spring Cloud Netflix 使用的是Eureka,而SpringCloudAlibaba 给我们提供的就是Nacos。
而且,Nacos比Eureka 更加强大,他还可以用来当配置中心。
这里我就简单的先完成他基本的职责:服务注册与发现。
首先nacos和Eureka有点不同。
他这个应用。不是我们自己写的,Eureka这个东西他需要我们自己创建一个应用。然后在编写代码,然后再将项目打包,在启动。
Nacos这个东西他和Zipkin有点像,是那种直接下载下来运行就完事了的。
我这儿用Docker来运行一个单机的 Nacos 镜像添加到8848端口(默认端口),当然,集群是肯定可以集群的,我这先不玩。
对了,不知道为啥我用网易的docker镜像地址下载会卡住,之后换了alibaba的来下就没问题了。
docker pull nacos/nacos-server docker run --env MODE=standalone --name nacos -d -p 8848:8848 nacos/nacos-server
nacos登陆地址:http://ip:8848/nacos 默认账号密码是nacos/nacos
开启Nacos服务完毕后,就要开始写服务提供者和服务消费者了。
其实这俩都差不多,反正注册进服务治理中心了,A可以调用B的服务,自然B也可以调用A的服务,导入的配置也一样,我这就以服务消费者来举例子,避免贴两份基本相同的代码了。
我这使用的是最新的版本,要用就用最新的,不然没意思。我之前写的Netflix项目也是使用的最新的,当时用的是SpringCloud F版第三版
现在这个项目用的是SpringCloud G版第三版,SpringBoot 2.1.8.RELEASE
先创个依赖项目进行最基本的统一依赖管理
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
</parent>
<groupId>com.skypyb</groupId>
<artifactId>sc-demo-alibaba-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>sc-demo-alibaba-dependencies</name>
<url>http://www.skypyb.com</url>
<inceptionYear>2019-Now</inceptionYear>
<properties>
<!-- Environment Settings -->
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring Settings -->
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
<spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!-- Compiler 插件, 设定 JDK 版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<!-- 打包 jar 文件时,配置 manifest 文件,加入 lib 包的 jar 依赖 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
<executions>
<execution>
<configuration>
<archive>
<manifest>
<!-- Add directory entries -->
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
<!-- resource -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
<!-- install -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
</plugin>
<!-- clean -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
</plugin>
<!-- ant -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
<!-- dependency -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!-- Java Document Generate -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<!-- 资源文件配置 -->
<resources>
<resource>
<directory>src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>aliyun-repos</id>
<name>Aliyun Repository</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>sonatype-repos</id>
<name>Sonatype Repository</name>
<url>https://oss.sonatype.org/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>sonatype-repos-s</id>
<name>Sonatype Repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>aliyun-repos</id>
<name>Aliyun Repository</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
这个项目集成了SpringBoot 然后导入了SpringCloud的依赖和SpringCloudAlibaba的依赖。
依赖项目写完之后就是正式开工编写服务。
这个服务就直接继承我刚刚写的依赖项目就可以了。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.skypyb</groupId>
<artifactId>sc-demo-alibaba-dependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../sc-demo-alibaba-dependencies/pom.xml</relativePath>
</parent>
<artifactId>sc-demo-alibaba-consumer</artifactId>
<packaging>jar</packaging>
<name>sc-demo-alibaba-consumer</name>
<url>http://www.skypyb.com</url>
<inceptionYear>2019-Now</inceptionYear>
<dependencies>
<!-- Spring Boot Begin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot End -->
<!-- Spring Cloud Begin -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Spring Cloud End -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.skypyb.provider.NacosConsumerApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
然后在其中,引入web、actuator、test几个SpringBoot依赖。当然还有必不可少的SpringCloudAlibaba Nacos 依赖。
启动类:
package com.skypyb.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient//nacos使用spring cloud 原生注解
public class NacosConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(NacosConsumerApplication.class, args);
}
}
这个启动类用了个 @EnableDiscoveryClient 这个注解,该注解是SpringCloud内置的,Nacos实现了这个注解,导入了Nacos的依赖的话就代表要注册进Nacos里边。
这样的好处就是以后要是换个新的服务治理中心,代码都不用改就可以轻易的更换,完美符合里式替换原则
既然能注册进去了,那接着还是老规矩,来个RestTemplate进行远程服务的调用,@LoadBalanced代表负载均衡,这些东西我以前的文章都有讲过啊,这儿就不详细说了。
package com.skypyb.provider.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestConfiguration {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
这里就是编写一个控制层,来进行接口对外暴露,内部就是使用RestTemplate+LoadBalancerClient 来进行负载均衡的调用其他服务。
package com.skypyb.provider.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RequestMapping("/consumer")
@RestController
public class NacosConsumerController {
@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private RestTemplate restTemplate;
@GetMapping(value = "/hello/{msg}")
public String hello(@PathVariable("msg") String msg) {
//使用 LoadBalanceClient 和 RestTemplate 结合的方式来访问
ServiceInstance serviceInstance = loadBalancerClient.choose("sc-demo-alibaba-provider");
String url = String.format("http://%s:%s/echo/%s",
serviceInstance.getHost(), serviceInstance.getPort(), msg);
return restTemplate.getForObject(url, String.class);
}
}
当然,yml是肯定要写的。
spring:
application:
name: sc-demo-alibaba-consumer
cloud:
nacos:
discovery:
server-addr: 192.168.1.14:8848 #注册进 nacos
server:
port: 8081
management:
endpoints:
web:
exposure:
include: "*"
对了,这个management.endpoints 下边端点一定得打开。
因为 SpringCloudAlibaba 的 Nacos 在实现的时候提供了一个 EndPoint, EndPoint 的访问地址为 http://ip:port/actuator/nacos-discovery。
这玩意和服务注册发现息息相关,要是Nacos访问不了这个端点,那你就注册不了。
其实到这就差不多了,服务已经可以注册进Nacos里了,然后微服务之间的互相调用也是没有问题的,负载均衡也可以实现。
都没啥好说的,只要学会SpringCloud的思想,组件从一套换成另一套也就几十分钟的时间。

1 COMMENT