前面的文章我们讲了服务的注册发现,本篇文章来讲一下如何在我们自己的服务中互相调用。
一、创建服务提供者集群
首先,我们创建一个父工程,工程名叫spring-cloud-demo,其中pom.xml文件配置如下:
注意修改其中nacos的配置为自己的配置,尤其是命名空间id的值<?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 https://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>3.1.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>top.jiangqiang</groupId> <artifactId>spring-cloud-demo</artifactId> <packaging>pom</packaging> <modules> <module>service-provider-01</module> <module>service-provider-02</module> <module>service-consumer</module> <module>service-gateway</module> <module>service-sentinel-feign-consumer</module> </modules> <version>${revision}</version> <name>${project.artifactId}</name> <description>spring-cloud-demo</description> <properties> <revision>1.0</revision> <java.version>17</java.version> <spring-cloud.version>2022.0.3</spring-cloud.version> <spring.cloud.alibaba.version>2022.0.0.0-RC2</spring.cloud.alibaba.version> </properties> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--提供了一些endpoint,可以查看项目信息--> <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> </dependencies> <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> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> <profiles> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <!-- 开发环境 --> <profile.name>dev</profile.name> <!--nacos服务访问地址--> <nacos.server-addr>127.0.0.1:8848</nacos.server-addr> <!--命名空间id--> <nacos.namespace>75d49a80-72f9-4b15-97b8-08ad100100b0</nacos.namespace> <!--nacos用户名和密码--> <nacos.username>nacos</nacos.username> <nacos.password>nacos</nacos.password> </properties> </profile> <profile> <id>test</id> <properties> <!-- 测试环境,打包命令:mvn clean install -Ptest --> <profile.name>test</profile.name> <nacos.server-addr>127.0.0.1:8848</nacos.server-addr> <nacos.namespace></nacos.namespace> <nacos.username></nacos.username> <nacos.password></nacos.password> </properties> </profile> </profiles> </project>
然后我们创建一个子模块作为其中一个服务,子模块名字为service-provider-01,pom.xml配置文件内容如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>top.jiangqiang</groupId> <artifactId>spring-cloud-demo</artifactId> <version>${revision}</version> </parent> <artifactId>service-provider-01</artifactId> <name>${project.artifactId}</name> <description>service-provider-01</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
application.yaml文件配置如下:
server: port: 8001 spring: application: name: service-provider #如果多个应用的此属性一致,会被注册中心识别为同一个应用的集群 cloud: nacos: username: @nacos.username@ password: @nacos.password@ config: server-addr: @nacos.server-addr@ #用于管理配置的nacos服务地址 namespace: @nacos.namespace@ #命名空间 discovery: server-addr: @nacos.server-addr@ #服务发现,服务注册中心地址,因为和配置中心使用同一个nacos,所以地址是同一个。 namespace: @nacos.namespace@ config: import: #springboot3必须配置此选项,至少配置一个,可以任意配置,配置后会使用nacos配置中心对应的配置 - optional:nacos:${spring.application.name}.yaml #前面加optional表示可选,允许配置服务器连接不成功时启动服务 - nacos:datasource.yaml?refresh=true #?refresh=true表示配置更新不需要重启即可生效,可以省略 - nacos:common.yaml management: endpoints: web: exposure: include: '*' #允许所有的endpoints访问,此时访问:http://127.0.0.1:8001/actuator/nacosdiscovery 可以看见nacos配置信息
新增一个controller类,内容如下:
@RestController public class TestController { @Value("${server.port}") private String port; @RequestMapping(value = "getPort") public String getPort() { return port; } }
将我们刚才创建的子模块service-provider-01复制一份,快速创建和他相同的另一个子模块,名字为service-provider-02。注意修改service-provider-02的端口号与子模块service-provider-01的端口号不一致,但是服务名必须一致(这样才能作为集群)。
service-provider-02修改后的yaml文件内容为:
server: port: 8002 spring: application: name: service-provider cloud: nacos: username: @nacos.username@ password: @nacos.password@ config: server-addr: @nacos.server-addr@ #用于管理配置的nacos服务地址 namespace: @nacos.namespace@ #命名空间 discovery: server-addr: @nacos.server-addr@ #服务发现,服务注册中心地址,因为和配置中心使用同一个nacos,所以地址是同一个。 namespace: @nacos.namespace@ config: import: #springboot3必须配置此选项,至少配置一个,可以任意配置,配置后会使用nacos配置中心对应的配置 - optional:nacos:${spring.application.name}.yaml #前面加optional表示可选,允许配置服务器连接不成功时启动服务 - nacos:datasource.yaml?refresh=true #?refresh=true表示配置更新不需要重启即可生效,可以省略 - nacos:common.yaml management: endpoints: web: exposure: include: '*' #允许所有的endpoints访问,此时访问:http://127.0.0.1:8002/actuator/nacosdiscovery 可以看见nacos配置信息
启动这两个模块后,我们就创建了一个简单的服务提供者集群,两个服务使用相同的服务名访问,可以使用nacos的负载均衡技术自动选择。
二、创建服务消费者服务
创建一个子模块service-consumer,pom.xml文件内容如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>top.jiangqiang</groupId> <artifactId>spring-cloud-demo</artifactId> <version>${revision}</version> </parent> <artifactId>service-consumer</artifactId> <name>${project.artifactId}</name> <description>service-consumer</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--必须依赖,用于负载均衡--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> <!--使用feign调用接口时必须依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> </project>
创建启动类如下:该类中,我们通过
@EnableFeignClients
注解启用feign客户端,并且注入了RestTemplate实例。@LoadBalanced注解的作用是提供负载均衡,框架底层已经为我们实现了负载均衡功能,此处我们只需要一个注解即可使用。当我们使用RestTemplate的实例调用集群中的服务时,程序会自动选择集群中的一个服务进行调用。具体如何选择,完全在于负载均衡策略。//该注解可以省略 @EnableDiscoveryClient @SpringBootApplication //使用feign客户端时必须 @EnableFeignClients public class ServiceConsumerApplication { @LoadBalanced @Bean public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(ServiceConsumerApplication.class, args); } }
RestTemplate可用于http接口访问,在此服务中我们使用RestTemplate的实例请求其他服务中的接口,这是一种服务之间的远程调用的方式。同时,我们也可以使用Feign作为另一种远程调用方式,而使用Feign进行远程调用时,会自动启用负载均衡功能。
创建Feign的服务类,用于调用远程接口:
@FeignClient(name = "service-provider") public interface FeignService { @GetMapping(value = "/getPort") String getPort(); }
创建一个controller类:
@RestController @RequestMapping("/") @RequiredArgsConstructor public class TestController { private final RestTemplate restTemplate; private final FeignService feignService; /** * 使用RestTemplate实例进行远程调用 * @return */ @RequestMapping(value = "/getPort1") public String getPort1() { return "RestTemplate:" + restTemplate.getForObject("http://service-provider/getPort", String.class); } /** * 使用Fetch进行远程调用 * @return */ @RequestMapping(value = "/getPort2") public String getPort2() { return "Feign:" + feignService.getPort(); } }
application.yaml文件中配置如下:注意loadbalancer这里的配置,如果不配置的话,默认的负载均衡是轮询策略,可以删掉该配置自己试试看。加上之后则是nacos提供的服务端负载均衡策略。
server: port: 8003 spring: application: name: service-consumer cloud: nacos: username: @nacos.username@ #@***@这种写法表示从pom.xml文件读取配置 password: @nacos.password@ config: file-extension: yaml server-addr: @nacos.server-addr@ #用于管理配置的nacos服务地址 namespace: @nacos.namespace@ #命名空间 discovery: server-addr: @nacos.server-addr@ #服务发现,服务注册中心地址,因为和配置中心使用同一个nacos,所以地址是同一个。 namespace: @nacos.namespace@ loadbalancer: #使用 Spring Cloud Alibaba 社区针对 Spring Cloud Loadbalancer 负载均衡依赖提供的负载均衡策略,以便使用 Spring Cloud Alibaba 提供的所有的能力 ribbon: enabled: false #关闭ribbon默认的轮询负载均衡策略 nacos: #使用nacos提供的负载均衡,不使用此配置时,默认的负载均衡是轮询 enabled: true config: import: #springboot3必须配置此选项,至少配置一个,可以任意配置,配置后会使用nacos配置中心对应的配置 - optional:nacos:${spring.application.name}.yaml #前面加optional表示可选,允许配置服务器连接不成功时启动服务 - nacos:datasource.yaml?refresh=true #?refresh=true表示配置更新不需要重启即可生效,可以省略 - nacos:common.yaml management: endpoints: web: exposure: include: '*' #允许所有的endpoints访问,此时访问:http://127.0.0.1:8003/actuator/nacosconfig 可以看见nacos配置信息
启动项目,然后多次访问:localhost:8003/getPort2 和localhost:8003/getPort1 根据端口号你可以看出请求最终是由哪个服务处理了,你会发现多次访问同一个接口,端口号会发生变化。这表明你的请求被分配给不同的服务了。如果删除yaml文件中loadbalancer相关的配置,你会发现连续两次请求会被分给不同的服务处理。
进入nacos后台,点击服务提供者集群的详情按钮。
详情页如图所示,我们点击下线按钮,再次访问上一步骤中的地址,看看有啥变化。
当我们下线其中一个服务后,我们的请求就会始终交给另一个没有下线的服务处理,如果是通过RestTemplate远程调用,下线过程可能有半分钟的延迟,半分钟之后我们的请求都会交给唯一没有下线的那个服务去处理。如果两个服务都被下线了,此时我们访问URL就会报错。很显然,当我们需要对某个服务进行重新部署时,最好先在此处点击下线,避免程序正在处理业务时,直接就被杀死。
评论区