微服务
项目代码: https://gitee.com/xuhx615/MyWFWDemo.git
🍓微服务技术栈
在国内最知名的微服务技术框架就是SpringCloud
和阿里巴巴的Dubbo
。
🍓微服务知识层次
🍓微服务特征
微服务是一种经过良好架构设计的分布式架构方案,微服务架构特征:
- 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
- 面向服务:微服务对外暴露业务接口
- 自治:团队独立、技术独立、数据独立、部署独立
- 隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题
🍓微服务技术对比
SpringCloudAlibaba
兼容前两种框架技术,通常我们使用SpringCloudAlibaba
🍓SpringCloud
SpringCloud
是目前国内使用最广泛的微服务框架。官网地址:https://spring.io/projects/spring-cloud。SpringCloud
集成了各种微服务功能组件,并基于SpringBoot
实现了这些组件的自动装配,从而提供了良好的开箱即用体验:
🍒SpringBoot与SpringCloud的兼容问题
🍒服务调用关系
- 服务提供者:暴露接口给其它微服务调用
- 服务消费者:调用其它微服务提供的接口
- 一个服务可以同时是服务提供者和服务消费者
🍓Eureka注册中心
🍒Eureka注册中心的作用
- 消费者该如何获取服务提供者具体信息?
- 服务提供者启动时向
eureka
注册自己的信息 eureka
保存这些信息- 消费者根据服务名称向
eureka
拉取提供者信息
- 服务提供者启动时向
- 如果有多个服务提供者,消费者该如何选择?
- 服务消费者利用负载均衡算法,从服务列表中挑选一个
- 消费者如何感知服务提供者健康状态?
- 服务提供者会每隔30秒向
EurekaServer
发送心跳请求,报告健康状态 eureka
会更新记录服务列表信息,心跳不正常会被剔除- 消费者就可以拉取到最新的信息
- 服务提供者会每隔30秒向
🍅Eureka的组成部分
在Eureka架构中,微服务角色有两类:
EurekaServer
:服务端,注册中心- 记录服务信息
- 心跳监控
EurekaClient
:客户端Provider
:服务提供者- 注册自己的信息到
EurekaServer
- 每隔
30
秒向EurekaServer
发送心跳
- 注册自己的信息到
consumer
:服务消费者- 根据服务名称从
EurekaServer
拉取服务列表 - 基于服务列表做负载均衡,选中一个微服务后发起远程调用
- 根据服务名称从
🍒代码整合
🍅父工程jar包统一版本控制
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version> <!--不要轻易改变他的版本,因为他跟Spring-cloud版本有兼容问题-->
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR10</spring-cloud.version>
<mysql.version>8.0.16</mysql.version>
<mybatis.version>2.1.1</mybatis.version>
</properties>
<!--jar包版本管理-->
<dependencyManagement>
<dependencies>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
🍅eureka注册中心
-
依赖:
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies>
-
配置文件
server.port=10086 #服务注册需要的信息(注意eureka本身也是需要注册的,所以他也需要配置下面的注册信息) #eureka服务名称(便于注册到eureka注册中心) spring.application.name=eurekaserver #需要注册到eureka服务集群的地址(eureka集群地址,多个用逗号隔开,除了ip和端口是自己配置的,其他是死的) eureka.client.service-url.defaultZone=http://127.0.0.1:10086/eureka
-
启动类
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer //开启eureka注册服务 @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class,args); } }
🍅eureka客户端服务
-
依赖:
<dependencies> <!--SpringBootWeb服务--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--eureka客户端依赖---> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <plugins> <!--SpringBoot打包插件--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
-
配置文件
server.port=8082 server.servlet.context-path=/orderService #服务注册需要的信息 #eureka客户端的服务名称 spring.application.name=orderservice #需要注册到eureka服务集群的地址 eureka.client.service-url.defaultZone=http://127.0.0.1:10086/eureka
-
启动类
import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class,args); } @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
-
访问
demo
import cn.wfw.xuhx.util.Result; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @CrossOrigin(origins = "*",maxAge = 3600) @RequestMapping("/order") public class OrderController { @Autowired private RestTemplate restTemplate; @RequestMapping(value = "/queryUser" ,produces = "application/json;charset=utf-8",method = RequestMethod.GET) public Result queryUser(){ //注意:通过eureka注册中心去访问另外一个服务器,这里就不能写另外一个服务器的ip和端口,需要写另外一个服务器在eureka注册中心注册的服务名称 return restTemplate.getForObject("http://userservice/userService/user/queryUser", Result.class); } }
🍓Nacos注册中心
Nacos
是阿里巴巴的产品,现在是SpringCloud
中的一个组件。相比Eureka
功能更加丰富,在国内受欢迎程度较高
nacos下载地址,注意当前1版本是稳定版,2版本的还处于测试阶段
🍒nacos启动
nacos
开箱即用,前往bin
目录输入命令 ./startup.cmd -m standalone
启动nacos
在浏览器输入:http://127.0.0.1:8848/nacos/index.html
即可,默认用户密码是nacos/nacos
🍒服务注册
naos
与eureka
都遵循Spring cloud common
的接口规范,所以只需引入对应的依赖和修改对应的配置即可,其他代码都不需要动。
🍅父工程添加nacos的jar包版本管理
<!--nacos的管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
🍅依赖添加
<!--去除之前eureka-client的依赖包,添加nacos-client的依赖包-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
🍅配置文件修改
配置文件只需修改一处,注册中心换成nacos
即可
spring.cloud.nacos.server-addr=http://127.0.0.1:8848
🍓负载均衡
🍒开启负载均衡
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
🍒负载均衡的原理
🍒负载均衡的策略
Ribbon
的负载均衡规则是一个叫做IRule
的接口来定义的,每一个子接口都是一种规则:
-
Ribbon
的负载均衡策略大概分两种:轮循(RoundRobinRule
)和随机(RandomRule
)。 -
默认策略是
ZoneAvoidanceRule
:按照zone
对服务器进行分组,按组进行轮循。 -
具体策略释义如下:
内置负载均衡规则类 规则描述 RoundRobinRule
简单轮询服务列表来选择服务器。它是 Ribbon
默认的负载均衡规则。AvailabilityFilteringRule
对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。(2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了 AvailabilityFilteringRule
规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit
属性进行配置。WeightedResponseTimeRule
为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。 ZoneAvoidanceRule
以区域可用的服务器为基础进行服务器的选择。使用 Zone
对服务器进行分类,这个Zone
可以理解为一个机房、一个机架等。而后再对Zone
内的多个服务做轮询。BestAvailableRule
忽略那些短路的服务器,并选择并发数较低的服务器。 RandomRule
随机选择一个可用的服务器。 RetryRule
重试机制的选择逻辑
🍒负载均衡策略的配置
- 全局配置(配置在启动类中)
@Bean public IRule randomRule(){ return new RandomRule(); }
- 指定服务名称配置(配置
application.properties
中)userservice.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
🍒负载均衡饥饿加载(配置application.properties中)
Ribbon
默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient
,请求时间会很长。
而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:
ribbon.eager-load.enabled=true
ribbon.eager-load.clients=userservice
🍓nacos服务分级存储模式
# 配置服务集群分组属性
spring.cloud.nacos.discovery.cluster-name=HZ
🍒与nacos服务分级存储模式搭配的负载均衡策略NacosRule
# 配置服务集群分组属性
userservice.ribbon.NFLoadBalancerRuleClassName=com.alibaba.cloud.nacos.ribbon.NacosRule
nacosRule负载均衡的策略:
- 优先选择同集群服务实例列表
- 本地集群找不到提供者,才去其它集群寻找,并且会报警告
- 确定了可用实例列表后,再采用随机负载均衡挑选实例
🍒加权负载均衡
根据部署的不同服务器的优劣,可以使用加权负载均衡,来控制它的访问权重,这个是nacos
可视化配置的,非常方便,权重大小介于0~1
之间,如下图所示:
🍓nacos命名空间
命名空间的作用就是隔离代码环境,即处于不同命名空间之间的服务是不能借助注册中心通信的。
🍒nacos命名空间的创建
-
使用可视化页面创建命名空间
-
将生成的命名空间ID配置到需要放置到该命名空间下的服务中去
spring.cloud.nacos.discovery.namespace=2728a8a7-f915-45bc-8196-2c527679ecc8
-
重启该服务
🍓nacos的临时实例和非临时实例
服务注册到nacos
中的实例默认都是临时实例。
临时实例和非临时实例的差别:
- 临时实例宕机时,会从
nacos
的服务列表中剔除,而非临时实例则不会。 - 临时实例定时向
nacos
发送心跳,当nacos
一段时间收不到心跳,就会认为该服务实例不健康,将其剔除出服务列表 - 非临时实例不会像
nacos
发送心跳,而是由nacos
注册中心定时向非临时实例发送请求询问其是否健康,当nacos
认为该服务实例不健康时,nacos
不会剔除该实例,而是等待它重新启动起来
配置服务实例为非临时实例:
spring.cloud.nacos.discovery.ephemeral=false
注意: 一般我们不会选择非临时实例,因为这样对于nacos
注册中心的服务压力就变大了。
🍓eureka与nacos的区别
Nacos
与eureka
的共同点- 都支持服务注册和服务拉取
- 都支持服务提供者心跳方式做健康检测
Nacos
与eureka
的区别Nacos
支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式- 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
Nacos
支持服务列表变更的消息推送模式,服务列表更新更及时Naco
s集群默认采用AP
方式,当集群中存在非临时实例时,采用CP
模式;eureka
采用AP
方式
🍓使用nacos实现动态配置管理
🍒实现流程
🍒具体步骤
-
在
nacos
可视化页面添加动态配置文件,文件名称格式:服务名称-名称空间.properties
或者服务名称-名称空间.yaml
-
在动态配置文件中编辑配置信息
-
在需要引入动态配置的项目中引入
nacos
动态配置的依赖,并添加bootstrap.properties
配置文件<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
#这五个决定了去哪里读取动态配置文件 #1. 服务注册需要的信息 #eureka客户端的服务名称 spring.application.name=orderservice #2. 动态配置文件的名称空间名称 spring.profiles.active=dev #3. 动态配置文件的后缀 spring.cloud.nacos.config.file-extension=properties #4. 动态配置文件的配置文件所在的名称空间ID(public可以省略,可以与项目不在一个名称空间) spring.cloud.nacos.config.namespace=2728a8a7-f915-45bc-8196-2c527679ecc8 #5. 需要注册到nacos服务集群的地址 spring.cloud.nacos.server-addr=http://127.0.0.1:8848
注意:
bootstrap.properties
只是比application.properties
加载的优先级更高,所以有些配置在bootstrap.properties
里面配置完成后就不需要在application.properties
重复配置 -
测试
//创建与之对应的配置类 import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component //ConfigurationProperties注解可以注入配置文件属性值,只需前缀与该类下的属性值相结合是配置文件的key即可,并且可以实现实时感知,比@Value注入要强大 @ConfigurationProperties(prefix = "message") public class MessageConfig { private Boolean switchStatus; public Boolean getSwitchStatus() { return switchStatus; } public void setSwitchStatus(Boolean switchStatus) { this.switchStatus = switchStatus; } }
🍓feignClient
使用feignClient
代替restTemplate
原因: restTemplate
存在下列问题:
- 代码可读性差,编程体验不统一
- 参数复杂
URL
难以维护
🍒使用步骤
-
引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
在启动类使用注解
@EnableFeignClients
开启feignClient
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableFeignClients //开启feignClient @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class,args); } }
-
创建
client
接口映射客户端服务接口import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @FeignClient("userservice") //服务实例名称 public interface UserServiceClient { //路径,请求方式 @RequestMapping(value = "/userService/user/queryUser",produces = "application/json;charset=utf-8",method = RequestMethod.GET) Result queryUser (); }
注意: feignClient
已经自动装配了Ribbon
负载均衡策略,所以关于负载均衡方面的配置无需修改。
-
feignClient
发送服务外的地址import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @FeignClient(url = "http://127.0.0.1:8081", name = "role-service") public interface RoleServiceClient { @GetMapping("/role/queryRoleList") Result queryRole(); }
-
单独给
feignClient
某个接口设置连接超时和读取超时import feign.Request; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestHeader; @FeignClient(value = "shop-service") public interface ShoppingServiceClient { @PostMapping("/shop/addShop") Result queryShopList(@RequestHeader(required = false, name = "options")Request.Options options, String req); }
🍒Feign性能优化
🍅Feign底层的客户端实现:
URLConnection
:默认实现,不支持连接池Apache HttpClient
:支持连接池OKHttp
:支持连接池
🍅Feign的日志级别
Feign
的日志级别主要有四种:NONE、BASIC、HEADERS、FULL
🍒Feign的优化性能主要包括:
- 使用连接池代替默认的
URLConnection
- 日志级别,最好用
basic
或none
🍒Feign优化性能的步骤
- 引入依赖
<dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency>
- 配置文件
# 设置feign的日志级别 feign.client.config.default.loggerLevel=BASIC # 设置feign客户端底层实现是支持连接池的httpclient feign.httpclient.enabled=true # 设置连接池的最大连接数 feign.httpclient.max-connections=200 # 设置一个连接的最大连接数 feign.httpclient.max-connections-per-route=50
🍓网关
🍒网关的作用
网关的作用:
- 对用户请求做身份认证、权限校验
- 将用户请求路由到微服务,并实现负载均衡
- 对用户请求做限流
🍒搭建Spring Cloud Gateway网关服务
-
注入依赖
<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>
-
配置文件
server.port=10010 spring.application.name=gateway spring.cloud.nacos.server-addr=http://127.0.0.1:8848 #路由ID,必须唯一 spring.cloud.gateway.routes[0].id=userservice #路由目标地址,可以是真实的ip + port(ttp://ip:port),也可以是注册在注册中心的实例名称(lb://实例名称),lb就是负载均衡 spring.cloud.gateway.routes[0].uri=lb://userservice #路由规则,设置路由规则 spring.cloud.gateway.routes[0].predicates[0]= Path=/userService/**
注意: 网关服务的实例也需要注册到注册中心
🍒路由规则工厂
名称 | 说明 | 示例 |
---|---|---|
After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
Between | 是某两个时间点之前的请求 | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate, ch.p |
Header | 请求必须包含某些header | - Header=X-Request-Id, \d+ |
Host | 请求必须是访问某个host(域名) | - Host=.somehost.org,.anotherhost.org |
Method | 请求方式必须是指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | - Path=/red/{segment},/blue/** |
Query | 请求参数必须包含指定参数 | - Query=name, Jack或者- Query=name |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
🍒路由过滤器
GatewayFilter
是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:
🍅路由过滤器工厂
过滤器工厂 | 功能 |
---|---|
RemoveRequestHeader | 移除请求中的一个请求头 |
AddResponseHeader | 给响应结果中添加一个响应头 |
RemoveResponseHeader | 从响应结果中移除有一个响应头 |
RequestRateLimiter | 限制请求的流量 |
AddRequestHeader | 添加请求头 |
AddRequestParameter | 添加请求参数 |
🍅路由过滤器配置
#局部过滤器
spring.cloud.gateway.routes[0].filters[0]= AddRequestHeader=Truth,Hello Spring Cloud!
#添加全局过滤器
spring.cloud.gateway.default-filters[0]= AddRequestHeader=Truth,Hello Spring Cloud!
🍅自定义过滤器
有些过滤业务并不简单,需要一定的逻辑代码才能实现,则gateway
提供的过滤工厂已不满足要求,可以使用自定义过滤器实现。
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 自定义过滤器,需要实现接口GlobalFilter
*/
@Order(-1) //过滤器执行优先级,值越小优先级越高
@Component
public class LoginFileter implements GlobalFilter {
/**
*
* @param exchange 可以获取到所有请求信息
* @param chain 放行用的
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
String user = queryParams.getFirst("user");
if("admin".equals(user)){
//放行
return chain.filter(exchange);
}
//拦截
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
注意: 自定义过滤器就是全局过滤器
🍅过滤器的执行顺序
- 每一个过滤器都必须指定一个
int
类型的order
值,order
值越小,优先级越高,执行顺序越靠前。 GlobalFilter
通过实现Ordered
接口,或者添加@Order
注解来指定order
值,由我们自己指定- 路由过滤器和
defaultFilter
的order
由Spring
指定,默认是按照声明顺序从1递增。 - 当过滤器的
order
值一样时,会按照defaultFilter
> 路由过滤器 >GlobalFilter
的顺序执行。
🍒跨域
跨域:域名不一致就是跨域,主要包括:
- 域名不同:
www.taobao.com
和www.taobao.org
和www.jd.com
和miaosha.jd.com
- 域名相同,端口不同:
localhost:8080
和localhost8081
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决方案:CORS
gateway解决跨域的配置:
#跨域解决
#解决options请求被拦截的问题 (options请求就是浏览器向服务器询问该请求是否可以跨域)
spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping=true
#允许哪些网站的跨域请求
spring.cloud.gateway.globalcors.cors-configurations.'[/**]'.allowed-origins[0]=http://localhost:8849
#允许的跨域ajax的请求方式
spring.cloud.gateway.globalcors.cors-configurations.'[/**]'.allowed-methods[0]=GET
spring.cloud.gateway.globalcors.cors-configurations.'[/**]'.allowed-methods[1]=POST
spring.cloud.gateway.globalcors.cors-configurations.'[/**]'.allowed-methods[2]=DELETE
spring.cloud.gateway.globalcors.cors-configurations.'[/**]'.allowed-methods[3]=PUT
spring.cloud.gateway.globalcors.cors-configurations.'[/**]'.allowed-methods[4]=OPTIONS
#允许在请求中携带的头信息
spring.cloud.gateway.globalcors.cors-configurations.'[/**]'.allowed-headers[0]=*
#是否允许携带cookie
spring.cloud.gateway.globalcors.cors-configurations.'[/**]'.allow-credentials=true
#这次跨域检测的有效期(这个值设置的越长,对系统的性能提高越好)
spring.cloud.gateway.globalcors.cors-configurations.'[/**]'.max-age=360000
🍓部署
Docker具体使用参考文档
这里我们采用Docker-Compose
去部署微服务集群
步骤分析:
- 建立一个文件夹,里面建立多个需要部署的服务的文件夹和一个
docker-compose.yml
文件
#版本 version: "3.2" #服务 services: nacos: #nacos服务 image: nacos/nacos-server environment: MODE: standalone #启动模式 ports: - "8848:8848" #暴露端口 userservice: #userservice服务 build: ./user-service orderservice: #orderservice服务 build: ./order-service gateway: #网关 build: ./gateway ports: - "10010:10010" #暴露端口
- 在每个服务文件夹下创建
Dockerfile
文件FROM java:8-alpine COPY ./app.jar /tmp/app.jar ENTRYPOINT java -jar /tmp/app.jar
- 修改所有微服务里的nacos注册中心的ip配置,因为部署后nacos的ip我们不一定知道,所以不能写死
#我们只需把ip改成集群部署对应的服务名即可,Docker-Compose会帮我们找到对应的容器 spring.cloud.nacos.server-addr=http://nacos:8848
- 将所有的微服务都打成名为app的jar包,并丢入各自的文件夹中
<build> <finalName>app</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
- 将此文件夹上传至服务器,在其
docker-compose.yml
所在目录下输入以下命令完成集群部署#1. 部署集群 [root@centos100 cloud-demo]# docker-compose up -d #2. 查看集群是否启动 [root@centos100 cloud-demo]# docker ps #3. 查看集群日志 [root@centos100 cloud-demo]# docker-compose logs -f #4. 如若发现有集群连不上nacos,查看集群启动顺序,如果nacos不是第一个启动,则会有问题,那么我们把剩下集群重新restart一下 [root@centos100 cloud-demo]# docker-compose restart gateway userservice orderservice