微服务架构

微服务

微服务技术栈

在国内最知名的微服务技术框架就是SpringCloud和阿里巴巴的Dubbo。
微服务架构
微服务架构

微服务知识层次

微服务架构

微服务特征

微服务是一种经过良好架构设计的分布式架构方案,微服务架构特征:

  • 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
  • 面向服务:微服务对外暴露业务接口
  • 自治:团队独立、技术独立、数据独立、部署独立
  • 隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题

微服务技术对比

微服务架构
SpringCloudAlibaba兼容前两种框架技术,通常我们使用SpringCloudAlibaba

SpringCloud

  • SpringCloud是目前国内使用最广泛的微服务框架。官网地址:https://spring.io/projects/spring-cloud
  • SpringCloud集成了各种微服务功能组件,并基于SpringBoot实现了这些组件的自动装配,从而提供了良好的开箱即用体验:
    微服务架构

SpringBoot与SpringCloud的兼容问题

微服务架构

服务调用关系

  • 服务提供者:暴露接口给其它微服务调用
  • 服务消费者:调用其它微服务提供的接口
  • 一个服务可以同时是服务提供者和服务消费者

Eureka注册中心

Eureka注册中心的作用

  • 消费者该如何获取服务提供者具体信息?
    • 服务提供者启动时向eureka注册自己的信息
    • eureka保存这些信息
    • 消费者根据服务名称向eureka拉取提供者信息
  • 如果有多个服务提供者,消费者该如何选择?
    • 服务消费者利用负载均衡算法,从服务列表中挑选一个
  • 消费者如何感知服务提供者健康状态?
    • 服务提供者会每隔30秒向EurekaServer发送心跳请求,报告健康状态
    • eureka会更新记录服务列表信息,心跳不正常会被剔除
    • 消费者就可以拉取到最新的信息
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注册中心
  1. 依赖:

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
    
  2. 配置文件

    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
    
  3. 启动类

    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客户端服务
  1. 依赖:

    	<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>
    
  2. 配置文件

    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
    
  3. 启动类

    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();
        }
    }
    
  4. 访问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命名空间的创建

  1. 使用可视化页面创建命名空间
    微服务架构
    微服务架构

  2. 将生成的命名空间ID配置到需要放置到该命名空间下的服务中去

    spring.cloud.nacos.discovery.namespace=2728a8a7-f915-45bc-8196-2c527679ecc8
    
  3. 重启该服务
    微服务架构

nacos的临时实例和非临时实例

服务注册到nacos中的实例默认都是临时实例。
微服务架构
临时实例和非临时实例的差别:

  • 临时实例宕机时,会从nacos的服务列表中剔除,而非临时实例则不会。
  • 临时实例定时向nacos发送心跳,当nacos一段时间收不到心跳,就会认为该服务实例不健康,将其剔除出服务列表
  • 非临时实例不会像nacos发送心跳,而是由nacos注册中心定时向非临时实例发送请求询问其是否健康,当nacos认为该服务实例不健康时,nacos不会剔除该实例,而是等待它重新启动起来

配置服务实例为非临时实例:

spring.cloud.nacos.discovery.ephemeral=false

注意: 一般我们不会选择非临时实例,因为这样对于nacos注册中心的服务压力就变大了。

eureka与nacos的区别

  • Nacos与eureka的共同点
    • 都支持服务注册和服务拉取
    • 都支持服务提供者心跳方式做健康检测
  • Nacos与Eureka的区别
    • Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
    • 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
    • Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
    • Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式

使用nacos实现动态配置管理

实现流程

微服务架构

具体步骤

  1. 在nacos可视化页面添加动态配置文件,文件名称格式:服务名称-名称空间.properties或者服务名称-名称空间.yaml
    微服务架构

  2. 在动态配置文件中编辑配置信息
    微服务架构

  3. 在需要引入动态配置的项目中引入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重复配置

  4. 测试

    	//创建与之对应的配置类
    	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难以维护

使用步骤

  1. 引入依赖

    	<dependency>
    	    <groupId>org.springframework.cloud</groupId>
    	    <artifactId>spring-cloud-starter-openfeign</artifactId>
    	</dependency>
    
  2. 在启动类使用注解@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);
        }
    }
    
  3. 创建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负载均衡策略,所以关于负载均衡方面的配置无需修改。

Feign性能优化

Feign底层的客户端实现:
  • URLConnection:默认实现,不支持连接池
  • Apache HttpClient :支持连接池
  • OKHttp:支持连接池
Feign的日志级别

Feign的日志级别主要有四种:NONE、BASIC、HEADERS、FULL

Feign的优化性能主要包括:

  1. 使用连接池代替默认的URLConnection
  2. 日志级别,最好用basicnone

Feign优化性能的步骤

  1. 引入依赖
    	<dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
    
  2. 配置文件
    	# 设置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网关服务

  1. 注入依赖

    	<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>
    
  2. 配置文件

    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值,由我们自己指定
  • 路由过滤器和defaultFilterorderSpring指定,默认是按照声明顺序从1递增。
  • 当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。

跨域

跨域:域名不一致就是跨域,主要包括:

  • 域名不同: www.taobao.comwww.taobao.orgwww.jd.commiaosha.jd.com
  • 域名相同,端口不同:localhost:8080localhost8081

跨域问题:浏览器禁止请求的发起者与服务端发生跨域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去部署微服务集群
步骤分析:

  1. 建立一个文件夹,里面建立多个需要部署的服务的文件夹和一个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"   #暴露端口
    
  2. 在每个服务文件夹下创建Dockerfile文件
    	FROM java:8-alpine
    	COPY ./app.jar /tmp/app.jar
    	ENTRYPOINT java -jar /tmp/app.jar
    
  3. 修改所有微服务里的nacos注册中心的ip配置,因为部署后nacos的ip我们不一定知道,所以不能写死
    	#我们只需把ip改成集群部署对应的服务名即可,Docker-Compose会帮我们找到对应的容器
    	spring.cloud.nacos.server-addr=http://nacos:8848
    
  4. 将所有的微服务都打成名为app的jar包,并丢入各自的文件夹中
    	<build>
            <finalName>app</finalName>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
  5. 将此文件夹上传至服务器,在其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
    
上一篇:关于注入,spring未自动装Bean的问题


下一篇:SpringCloud学习1-服务注册与发现(Eureka)