基于spring cloud alibaba 搭建微服务。
父工程的创建
父工程选择使用spring boot 2.3.0.RELEASE
,JDK 8,idea 2021,Windows 10。
<?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>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.noel.cloud</groupId>
<artifactId>alibaba</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>alibaba</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
</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>
</project>
编辑器生成代码后,添加cloudHoxton.SR3
和alibaba cloud
。spring boot-> spring cloud-> spring cloud alibaba。
服务治理中心
如上图所示的微服务群,各个微服务往服务治理中心注册服务,即充当服务提供者角色;然后其它微服务通过服务治理中心获取其它服务的信息,并调用这些服务,此时充当服务消费者角色。其中服务治理中心使用naocs实现。
nacos下载1.2.1,因为使用的alibaba版本,对应的nacos可以选择1.2.1:
下载后解压到一个位置,然后双击bin\startup.cmd
即启动服务治理中心,通过http://localhost:8848/nacos
即可访问,默认访问端口是8848
,用户名和密码均是nacos
。
服务提供者
使用springboot 创建子模块,不用选择依赖,生成代码后更改继承关系,更改<parent>
数据:
然后添加nacos依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
最后配置spring boot项目:
spring:
cloud:
nacos:
discovery:
server-addr: nacos的ip或者域名:nacos的端口
application:
name: provider #指定当前项目的名称,便于在nacos中显示
启动项目,即可在nacos网页中,即可看见运行的服务提供者:
服务消费者
父工程中创建一个子模块,创建和修改继承关系和提供者一样,而且应为需要通过nacos获取服务,所以也需要添加和提供者一样的nacos服务。消费者调用提供者的方法有几个方法,下面一次列举,消费者的端口定义为8180:
方法一,获取所有服务提供者:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/instance")
public List<ServiceInstance> instances(){
List<ServiceInstance> providers = this.discoveryClient.getInstances("provider");
return providers;
}
}
获取nacos上所注册的所有服务提供者,provider
为服务器提供者的application-name
。
方法二,调用服务提供者的某些方法:
服务提供方:
@RestController
public class ProviderController {
@Value("${server.port}")
private String port;
@GetMapping("/index")
public String index(){
//实现一个简单的返回服务提供者的端口功能
return this.port;
}
}
消费者:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
/**
* @Description 服务消费者,调用服务提供者的方法,获取其返回的端口数据。
* @Author noel
* @Date 2021/7/19
* Version 1.0
**/
@RestController
public class ConsumerController {
//使用springboot 集成的Nacos客户端发现功能,自动注入
@Autowired
private DiscoveryClient discoveryClient;
//restTemplate 需要手动注入,通过添加配置类实现
@Autowired
private RestTemplate restTemplate;
/**
* 通过nacos获取“provider”服务,如果该服务有集群,则随机获取其中一个
**/
@GetMapping("/index")
public String index(){
List<ServiceInstance> provider = this.discoveryClient.getInstances("provider");
int index = ThreadLocalRandom.current().nextInt(provider.size());
ServiceInstance serviceInstance = provider.get(index);
String url = serviceInstance.getUri()+ "/index";//服务提供者的接口
//指定String.class是因为服务提供者返回的是字符串
return "调用的端口是"+serviceInstance.getPort()+"的服务,返回结果是:"+ restTemplate.getForObject(url, String.class);
}
}
// ========================================
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @Description 将RestTemplate配置为Bean
* @Author noel
* @Date 2021/7/22
* Version 1.0
**/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
服务消费者照普通spring boot项目启动后,访问index
接口即对服务提供者产生了调用。
Ribbon优化服务消费者
在使用springcloud的时候,就已经加载了Ribbon,然后修改两个地方即有效的使用Ribbon进行负载均衡,这是客户端负载均衡,而且比上面的客户端使用随机数调用服务者更优雅。
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced //增加的注解,
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
在RestTemplate配置类中,添加@LoadBalanced
注解,即表明调用方式使用了负载均衡。此处默认使用了轮询的方式。
@GetMapping("/index")
public String index(){
// List<ServiceInstance> provider = this.discoveryClient.getInstances("provider");
// int index = ThreadLocalRandom.current().nextInt(provider.size());
// ServiceInstance serviceInstance = provider.get(index);
// String url = serviceInstance.getUri()+ "/index";
// return "调用的端口是"+serviceInstance.getPort()+"的服务,返回结果是:"+ restTemplate.getForObject(url, String.class);
return this.restTemplate.getForObject("http://provider/index", String.class);
}
只需指明服务提供者的地址即可,其中访问地址中的provider
使用的是服务提供者的application name
值。
P.S. 课程参考