中秋佳节,来玩一波 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