1、服务注册与发现(Nacos)
-
导入依赖
<!-- Nacos 整合 SpringCloud--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
-
修改配置文件
spring: application: name: order-service #服务名称 注册到注册中心的服务名称 cloud: nacos: discovery: server-addr: localhost:8848 #注册与发现中心地址
-
启动Nacos 重启服务 检查Nacos控制台的
服务管理·服务列表
2、远程调用(OpenFeign)
-
服务必须已注册到Nacos控制平台
-
服务消费方 导入依赖
<!-- 远程调用 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
服务提供方 提供接口
@RestController @RequestMapping("/storage") public class StorageController { @Autowired StorageService storageService; /** * 库存扣减接口 post /storage/deduct */ @PostMapping("/deduct") public ResultVO<Object> deduct(@RequestParam String commodityCode, int count) { storageService.deduct(commodityCode, count); return ResultVO.success(); } /** * post + json */ @PostMapping("/json") public ResultVO<Object> deductJson(@RequestBody Storage storage) { storageService.deduct(storage.getCommodityCode(), storage.getCount()); return ResultVO.success(); } @GetMapping("/{code}") public ResultVO<Storage> getStorage(@PathVariable String code) { Storage storage = storageService.getStorage(code); return ResultVO.success(storage); } @PutMapping("/{id}") public ResultVO<Storage> update(@PathVariable int id, @RequestBody Storage storage) { return ResultVO.success(); } }
-
服务消费方 声明远程服务接口
/* * 远程服务接口 * 接口地址: http://storage-service/storage/deduct * * @FeignClient(name = "要调用的服务spring.application.name的值" ) */ @FeignClient(name = "storage-service") public interface StorageService { /** * post/put/get/delete + form * 1、参数是基本数据类型及其包装类、String:必须在所有的参数前必须加上@RequestParam * 2、参数是Java Bean: 必须在Java Bean前增加 @SpringQueryMap */ @PostMapping("/storage/deduct") ResultVO<Object> deduct(@RequestParam String commodityCode, @RequestParam int count); // ResultVO<Object> deduct2(@SpringQueryMap Storage storage); /** * post/put/delete + json * 发送JSON的请求, 几乎不需要修改 */ @PostMapping("/storage/json") ResultVO<Object> deductJson(@RequestBody Storage storage); // ResultVO<Object> deductJson(@RequestBody Order order); @GetMapping("/storage/{code}") ResultVO<Storage> getStorage(@PathVariable String code); @GetMapping("/storage/{id}") ResultVO<Storage> update(@PathVariable int id, @RequestBody Storage storage); }
-
在启动类上增加注解:,为远程服务接口创建代理对象
@SpringBootApplication @MapperScan(basePackages = "com.exec.**.mapper") @EnableTransactionManagement // @EnableFeignClients(basePackages = "com.exec.**.api") @EnableFeignClients public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } }
-
使用远程服务接口
@Service public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService { //注入远程服务接口 @Autowired StorageService storageService; /** 创建订单 */ @Override @Transactional(rollbackFor = Exception.class) public void createOrder(Order order) { // 扣减库存 ResultVO<Object> resultVO = storageService.deduct(order.getCommodityCode(), order.getCount()); System.out.println(resultVO); save(order); } }
3、负载均衡(loadbalancer)
-
导入依赖
<!-- 负载均衡组件 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
-
只要导入依赖,负载均衡自动实现,默认是 轮询
4、配置中心(Nacos)
在系统开发过程中,开发者通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的 是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物理运行环境进行适配。
配置管理一般包含在系统部署的过程中,由系统管理员或者运维人员完成。配置变更是调整系统运行时行为的有效手段。
1. 核心概念
-
一个具体的可配置的参数与其值域,通常以 key=value 的形式存在。
-
例如:配置系统的日志输出级别logLevel=INFO|WARN|ERROR ) 就是一个配置项。
-
-
一组相关或者不相关的配置项的集合称为配置集。在系统中,一个配置文件(如application.yml)通常就是一个配置集,包含了系统各 个方面的配置。例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。
-
配置集 ID 是组织划分配置的维度之一。Data ID 通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配 置集都可以被一个有意义的名称标识。Data ID 通常采用类 Java 包(如 com.taobao.tc.refund.log.level)的命名规则保证全局唯一 性,此命名规则非强制。
-
Nacos 中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串(如 Buy 或 Trade )对配置集进行分组,从而区分 Dat a ID 相同的配置集。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如 database_url 配置 和 MQ_topic 配置。
-
在 Nacos Spring Cloud 中, dataId 的完整格式如下
${prefix}-${spring.profiles.active}.${file-extension}
-
${prefix}
-
默认值:spring.application.name 的值
-
如何修改:spring.cloud.nacos.config.prefix = ${spring.application.name}
-
-
${spring.profiles.active}
-
默认值:没有默认值
-
如何修改:spring.profiles.active = dev
-
-
${file-extension}
-
默认值:properties
-
如何修改:spring.cloud.nacos.config.file-extension = properties
-
-
2. 使用配置中心
bootstrap配置文件,一般添加 nacos配置中心的相关信息。项目的信息还是放到 application配置文件中。
注意:
必须使用 bootstrap.properties或者 bootstrap.yaml配置文件来配置 Nacos Server 地址。‘
-
导入依赖
<!-- spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 注册与发现中心 spring-cloud-starter-alibaba-nacos-discovery --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--===== Nacos配置中心 + bootstrap start =====--> <!-- 配置中心 spring-cloud-starter-alibaba-nacos-config --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!-- bootstrap.yml | bootstrap.properties || spring-cloud-starter-bootstrap --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> <!--===== Nacos配置中心 + bootstrap end =====-->
-
编写
bootstrap.yml
文件server: port: 9003 spring: application: # 服务名称(注册到Nacos中的服务的名称) name: config-service profiles: active: dev cloud: nacos: # 注册与发现中心地址 discovery: server-addr: localhost:8848 # 配置中心 config: server-addr: ${spring.cloud.nacos.discovery.server-addr} # prefix可以省略, 它的默认值就是 spring.application.name 的值 prefix: ${spring.application.name} # 默认值是properties file-extension: yml
-
创建启动类
-
在Nacos配置中心创建Data ID
全部采用默认值:
1、Data ID:config-serivce(这个就是spring.application.name的值)内容格式是 properties 格式
2、Data ID:config-service.properties
仅增加 spring.profiles.active = dev 配置项
1、Data ID:config-serivce(这个就是spring.application.name的值)内容格式是 properties 格式
2、Data ID:config-service.properties
3、Data ID:config-service-dev.properties
修改 file-extension 的值
1、Data ID:config-serivce(这个就是spring.application.name的值)内容格式是 yaml 的格式
2、Data ID:config-service.yml
3、Data ID:config-service-dev.yml
配置优先级
3. Nacos配置持久化
Nacos 默认使用内置数据库 Apache Derby 数据库保存配置中心数据
将Nacos 配置中心使用的数据库切换为外部数据库 - MySQL
-
数据库
-
在数据库中创建表: 导入 nacos/conf/mysql-schema.sql 文件
-
修改Nacos配置
修改nacos/conf/application.properties
#*************** Config Module Related Configurations ***************# ### If use MySQL as datasource: ### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced. # spring.datasource.platform=mysql spring.sql.init.platform=mysql ### Count of DB: db.num=1 ### Connect URL of DB: db.url.0=jdbc:mysql://127.0.0.1:3306/et2402_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user.0=root db.password.0=root
-
重启Nacos
4. 动态加载配置中心的配置项
-
使用 @Value 获取配置项:在当前Spring Bean对象上使用@RefreshScope
@RestController
// 自动刷新使用@Value获取的配置项
@RefreshScope
public class TestController {
@Value("${user.id}")
private int id;
@Value("${user.name}")
private String username;
@RequestMapping("/test")
public ResultVO<Object> test() {
Map<Object, Object> userMap = MapUtil.builder()
.put("id", id)
.put("name", username)
.build();
return ResultVO.success(userMap);
}
}
-
使用@ConfigurationProperties 获取配置项:可以自动刷新配置
@Data
@Component
// 读取 配置中心 或 本地配置文件中的以user开头的配置项
@ConfigurationProperties(prefix = "user")
public class UserProperties {
/** 成员变量名称就是二级配置项 */
private int id;
/** 成员变量名称就是二级配置项 */
private String name;
}
5、网关(gateway)
1. 网关介绍
网关(Gateway)组件是指用于构建具有统一入口的微服务架构中的一个组件,它可以实现动态路由、负载均衡、熔断、安全控制等功能。它的目标是为微服务架构提供⼀种简单、有效的、统⼀的API路由管理方式,且基于 Filter 链的方式提供了网关基本的功能,例如:安全、限流、熔断、路径重写、日志监控等功能。在微服务架构中,每个服务都有自己的入口,客户端需要知道每个服务的地址和端口号才能访问它们。而网关组件可以为所有服务提供一个统一的入口,客户端只需要知道网关的地址和端口号,就可以通过网关访问所有的服务。
三大核心概念
-
路由(route):路由是网关最基础的部分,路由信息由一个ID,一个目的URL、一组断言工厂和一 组Filter组成。如果断言为真,则说明请求URL和配置的路由匹配。
-
断言(Predicate):Java8中的断言函数,Spring Cloud Gateway中的断言函数输入类型是 Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配 来自http Request中的任何信息,比如请求头和参数等。
-
过滤器(Filter):一个标准的Spring WebFilter,Spring Cloud Gateway中的Filter分为两种类型: Gateway Filter和Global Filter。过滤器Filter可以对请求和响应进行处理
2. 网关使用并实现负载均衡
-
创建网关:gateway-01,配置Maven依赖
<dependency>
<!-- 网关 -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<!-- 服务注册与发现 -->
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<!-- 负载均衡 -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
-
编写配置文件:application.yml
server:
port: 9006
spring:
application:
name: gateway03
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/order-system/**
filters:
- StripPrefix=1
- id: storage-service
uri: lb://storage-service
predicates:
- Path=/storage-system/**
filters:
- StripPrefix=1
3. 将路由配置放到 Nacos 配置中心
-
导入依赖
<dependencies>
<!-- spring-cloud-starter-gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- spring-cloud-starter-loadbalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- Nacos注册与发现中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- spring-cloud-starter-bootstrap -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
-
bootstrap.yml
server:
port: 9006
spring:
application:
name: gateway03
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yml
-
Nacos配置中心
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/order-system/**
filters:
- StripPrefix=1
- id: storage-service
uri: lb://storage-service
predicates:
- Path=/storage-system/**
filters:
- StripPrefix=1
4. 创建全局过滤器,检查token是否为空
创建全局过滤器:默认应用到所有的Route
1、实现GlobalFilter
2、实现 Ordered 接口进行过滤器排序
@Component
public class TokenFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 请求对象
ServerHttpRequest request = exchange.getRequest();
// 响应对象
ServerHttpResponse response = exchange.getResponse();
String token = request.getHeaders().getFirst("token");
if (StringUtils.isEmpty(token)) {
return noAuth(response, ResultEnum.TOKEN_IS_NULL);
}
return chain.filter(exchange);
}
private Mono<Void> noAuth(ServerHttpResponse response, ResultEnum resultEnum) {
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
ResultVO<Object> resultVO = ResultVO.failed(resultEnum);
String resultJson = JSONUtil.toJsonStr(resultVO);
// WebFlux
DataBuffer dataBuffer = response.bufferFactory().wrap(resultJson.getBytes());
return response.writeWith(Mono.just(dataBuffer));
}
@Override
public int getOrder() {
return -200;
}
}