父项目
创建一个maven项目l-cloud-alibaba,将src目录删除,修改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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codelong</groupId>
<artifactId>l-cloud-alibaba</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<!-- 公共模块-->
<module>cloud-common</module>
<module>cloud-nacos-register</module>
<module>cloud-nacos-consumer</module>
</modules>
<properties>
<java.version>1.8</java.version>
<encoding>UTF-8</encoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<spring-cloud-alibaba.version>2.2.2.RELEASE</spring-cloud-alibaba.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- 第三方依赖版本-->
<lombok.version>1.18.20</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.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>
<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>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
复制代码
为了方便我放一些公共的依赖和代码,我们创建一个cloud-common
模块,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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>l-cloud-alibaba</artifactId>
<groupId>com.codelong</groupId>
<version>1.0.0</version>
</parent>
<packaging>jar</packaging>
<artifactId>cloud-common</artifactId>
<name>common</name>
<description>公共模块</description>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
</dependencies>
</project>
复制代码
然后在com.codelong.base
包下分别创建Result.java
和CodeAndMsg.java
分别代表统一响应内容封装和状态码封装
Result.java
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
/**
* 响应体封装
*
* @param <T>
* @author codelong
* @since 1.0
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@Slf4j
@Data
public class Result<T> implements Serializable {
/**
* 状态码
*/
private int status;
/**
* 消息
*/
private String message;
/**
* 数据
*/
private T data;
private boolean success;
private long timestamp;
public Result() {
this.timestamp = System.currentTimeMillis();
}
private Result(int status, String message, boolean success) {
this();
this.status = status;
this.message = message;
this.success = success;
}
private Result(int status, String message, boolean success, T data) {
this(status, message, success);
this.data = data;
}
private Result(CodeAndMsg codeAndMsg, boolean success) {
this();
this.status = codeAndMsg.getCode();
this.message = codeAndMsg.getMessage();
this.success = success;
}
private Result(CodeAndMsg codeAndMsg, boolean success, T data) {
this(codeAndMsg, success);
this.data = data;
}
/**
* 创建成功的响应
*/
public static <T> Result<T> success(int status, String message) {
return new Result<T>(status, message, true);
}
public static <T> Result<T> success(CodeAndMsg codeAndMsg) {
return new Result<T>(codeAndMsg, true);
}
public static <T> Result<T> success(int status, String message, T data) {
return new Result<T>(status, message, true, data);
}
public static <T> Result<T> success(CodeAndMsg codeAndMsg, T data) {
return new Result<T>(codeAndMsg, true, data);
}
/**
* 创建失败的响应
*/
public static <T> Result<T> fail(int status, String message) {
return new Result<T>(status, message, false);
}
public static <T> Result<T> fail(CodeAndMsg codeAndMsg) {
return new Result<T>(codeAndMsg, false);
}
}
复制代码
CodeAndMsg.java
/**
* 状态码集合
*
* @author codelong
* @since 1.0
*/
public enum CodeAndMsg {
/**
* 操作成功
**/
RC100(100, "请求成功"),
/**
* 操作失败
**/
RC999(999, "操作失败"),
/**
* 服务限流
**/
RC200(200, "服务开启限流保护,请稍后再试!"),
/**
* 服务降级
**/
RC201(201, "服务开启降级保护,请稍后再试!"),
/**
* 热点参数限流
**/
RC202(202, "热点参数限流,请稍后再试!"),
/**
* 系统规则不满足
**/
RC203(203, "系统规则不满足要求,请稍后再试!"),
/**
* 授权规则不通过
**/
RC204(204, "授权规则不通过,请稍后再试!"),
/**
* access_denied
**/
RC403(403, "匿名用户访问无权限资源时的异常"),
/**
* access_denied
**/
RC401(401, "认证用户访问无权限资源时的异常");
/**
* 自定义状态码
**/
private final int code;
/**
* 自定义描述
**/
private final String message;
CodeAndMsg(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
复制代码
创建微服务
我们这里使用提供者(cloud-nacos-register)和消费者(cloud-nacos-consumer)来模拟微服务之间的调用。
创建cloud-nacos-register微服务
在父模块下创建一个子模块cloud-nacos-register。
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>
<artifactId>l-cloud-alibaba</artifactId>
<groupId>com.codelong</groupId>
<version>1.0.0</version>
</parent>
<artifactId>cloud-nacos-register</artifactId>
<name>register-service</name>
<description>服务提供者</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
复制代码
然后在controller包下创建一个RegisterController类,提供一个接口给消费者调用,RegisterController内容如下:
import org.springframework.beans.factory.annotation.Value;
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;
@RestController
@RequestMapping("provider")
public class RegisterController {
@Value("${server.port}")
String port;
@GetMapping("{message}")
public String hello(@PathVariable String message) {
return String.format("%s from %s", message, port);
}
}
复制代码
修改application.yml文件,内容如下:
server:
port: 8001 # 服务端口号
spring:
application:
name: provider-service # 服务名称,默认也是在微服务中注册的微服务ID
cloud:
nacos:
server-addr: 127.0.0.1:8848 # 指定Nacos注册中心的地址
username: nacos # Nacos服务器的用户名,默认为 nacos
password: nacos # Nacos服务器的密码,默认为 nacos
复制代码
创建cloud-nacos-consumer微服务
在父模块下创建一个子模块cloud-nacos-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>
<artifactId>l-cloud-alibaba</artifactId>
<groupId>com.codelong</groupId>
<version>1.0.0</version>
</parent>
<artifactId>cloud-nacos-consumer</artifactId>
<name>consumer-service</name>
<description>服务消费者</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
复制代码
然后在controller包下创建一个ConsumerController类,提供一个接口调用上面的服务,ConsumerController内容如下:
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;
import javax.annotation.Resource;
@RestController
@RequestMapping("consumer")
public class ConsumerController {
@Resource
private RestTemplate restTemplate;
@GetMapping("/{message}")
public String hello(@PathVariable String message) {
// 关键点:将原有IP:端口替换为服务名,RestTemplate便会在通信前自动利用Ribbon查询可用provider-service实例列表
// 再根据负载均衡策略选择节点实例
return restTemplate.getForObject(String.format("http://provider-service/provider/%s", message), String.class);
}
}
复制代码
然后在configure包下创建一个ConsumerConfigure配置类,注入RestTemplate并加上@LoadBalanced注解来支持Ribbon负载均衡:
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 ConsumerConfigure {
@Bean
@LoadBalanced // 使RestTemplate对象自动支持Ribbon负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
复制代码
修改application.yml文件,内容如下:
server:
port: 9001 # 服务端口号
spring:
application:
name: consumer-service # 服务名称,默认也是在微服务中注册的微服务ID
cloud:
nacos:
server-addr: 127.0.0.1:8848 # 指定Nacos注册中心的地址
username: nacos # Nacos服务器的用户名,默认为 nacos
password: nacos # Nacos服务器的密码,默认为 nacos
logging:
level:
root: debug # 为了方便看日志,只在开发时开启,正式不要开
复制代码
这里将logging设置成debug级别是为了方便看到负载均衡调用的日志。
最终项目结构如下
启动提供者和消费者
分别启动cloud-nacos-register
和cloud-nacos-consumer
项目
登录Nacos控制台查看服务列表:
可以看到,两个服务都注册进来了。接着浏览器访问:http://localhost:9001/consumer/nacos:
调用成功,说明服务发现成功。
测试负载均衡
如下图所示,在ProviderApplication上右键选择Copy Configuration…:
然后按照下图所示填写相关内容:
然后启动刚刚复制的服务
登录Nacos控制台查看服务列表发现provider有2个实例
然后多次访问:http://localhost:9001/consumer/nacos,可以看到请求是均衡的(默认为轮询算法):
Nacos注册中心配置
配置项 | Key | 默认值 | 说明 |
---|---|---|---|
服务端地址 | spring.cloud.nacos.discovery.server-addr |
Nacos服务器侦听器的IP和端口 | |
Service name | spring.cloud.nacos.discovery.service |
${spring.application.name} |
当前服务名称 |
服务分组 | spring.cloud.nacos.discovery.group |
设置服务所处的分组 | |
权重 | spring.cloud.nacos.discovery.weight |
1 |
取值范围:1到100。值越大,权重越大 |
网卡名 | spring.cloud.nacos.discovery.network-interface |
如果未指定IP地址,则注册的IP地址是网卡的IP地址。如果也未指定,则默认情况下将使用第一张网卡的IP地址。 | |
注册的IP地址 | spring.cloud.nacos.discovery.ip |
优先级最高 | |
注册的端口 | spring.cloud.nacos.discovery.port |
-1 |
默认情况下不用配置,会自动探测 |
命名空间 | spring.cloud.nacos.discovery.namespace |
常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。 | |
AccessKey | spring.cloud.nacos.discovery.access-key |
当要上阿里云时,阿里云上面的一个云账号名 | |
SecretKey | spring.cloud.nacos.discovery.secret-key |
当要上阿里云时,阿里云上面的一个云账号密码 | |
Metadata | spring.cloud.nacos.discovery.metadata |
使用Map格式配置,用户可以根据自己的需要自定义一些和服务相关的元数据信息 | |
日志文件名 | spring.cloud.nacos.discovery.log-name |
||
集群名 | spring.cloud.nacos.discovery.cluster-name |
DEFAULT |
配置成Nacos集群名称 |
接入点 | spring.cloud.nacos.discovery.endpoint |
地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址 | |
是否集成Ribbon | ribbon.nacos.enabled |
true |
一般都设置成true即可 |
是否开启Nacos Watch | spring.cloud.nacos.discovery.watch.enabled |
true |
可以设置成false来关闭 watch |