Linfinity

Never say never.
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

springcloud笔记

Posted on 2020-10-18 21:25  Linfinity  阅读(197)  评论(0编辑  收藏  举报

一、springcloud介绍

1.1、RPC和HTTP

无论是微服务还是SOA,都面临着服务间的远程调用。那么服务间的远程调用方式有哪些呢?

常见的远程调用方式有以下2种:

  • RPC:Remote Produce Call远程过程调用,类似的还有RMI。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的webservice,现在热门的dubbo,都是RPC的典型代表

  • Http:http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。缺点是消息封装臃肿,优势是对服务的提供和调用方没有任何技术限定,自由灵活,更符合微服务理念。springcloud就是基于http。

 

1.2、springcloud核心组件

五大重要组件
服务发现——Netflix Eureka
客服端负载均衡——Netflix Ribbon/Feign
服务网关——Netflix Zuul
断路器——Netflix Hystrix
分布式配置——Spring Cloud Config

 

 

1.3、快速案例

1)parent

<?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>org.example</groupId>
    <artifactId>father</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>../springcloud-study/common</module>
    </modules>
    <packaging>pom</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>


    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR2</version>
            <type>pom</type>
<!--            import表示将spring-cloud-dependencies包中的依赖信息导入-->
            <scope>import</scope>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.2.9.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>



</project>
pom.xml

 

2)provider(springboot工程)

package com.example.provider.web;


import org.example.domain.Dog;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DogController {

    @RequestMapping("/dog")
    public Dog getDog(){
        return new Dog("肥松", 2);
    }

}

 

3)consumer(springboot工程)

package com.example.consumer.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class SpringCloudConfig {

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}
SpringCloudConfig.class
package com.example.consumer.web;

import org.example.domain.Dog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class RemoteDogController {
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/dog/remote")
    public Dog getDogRemote() {
        //1.准备provider的主机加端口
        String addr = "http://localhost:8989";

        //2.远程调用接口地址
        String api = "/provider/dog";

        //Dog.class 返回类型
        return restTemplate.getForObject(addr+api, Dog.class);
//        return new Dog("didi", 11);
    }
}
RemoteDogController.class

 

4)common(实体类必须要有无参数构造)

package org.example.domain;

public class Dog {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Dog(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Dog() {
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
Dog.class

 

 

二、eureka-注册中心

Eureka是netflix的一个子模块,也是核心模块之一,Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移
服务注册与发现对于微服务架构来说是非常重要的,有了服务发现和注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务,而不需要修改服务调用的配置文件了。

 

2.1、eureka服务端

1)创建springboot web项目,添加依赖

     <!--Eureka服务端支持:此依赖需放在其他依赖下面,否则可能启动不了-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>

 

2)在主启动类添加注解

 

 

3)配置

server.port=5000

eureka.instance.hostname=localhost

#实例是否在eureka服务器上注册自己的信息以供其他服务发现,默认为true
eureka.client.register-with-eureka=false
#此客户端是否获取eureka服务器注册表上的注册信息,默认为true
eureka.client.fetch-registry=false

#与Eureka注册服务中心的通信zone和url地址
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

 

4)启动服务,登录 http://localhost:5000 查看

 

2.2、provider客户端

1)添加依赖

        <!--Eureka服务端支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>

 

2)配置

server.port=8989
server.servlet.context-path=/provider

spring.application.name=provider01  //添加服务名称,方便调用

eureka.client.service-url.defaultZone=http://localhost:5000/eureka

 

2.3、consumer客户端

1)添加依赖

     <!--Eureka服务端支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>

 

2)配置

server.servlet.context-path=/consumer

spring.application.name=consumer01

eureka.client.serviceUrl.defaultZone=http://localhost:5000/eureka

 

3)在配置类添加注解

 

 

4)修改调用方式

package com.example.consumer.web;

import org.example.domain.Dog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class RemoteDogController {
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/ribbon/dog/remote",produces = "application/json;charset=utf-8")
    public Dog getDogRemote() {
        //1.准备provider的主机加端口
//        String addr = "http://localhost:8989";
        String addr = "http://provider01";

        //2.远程调用接口地址
        String api = "/provider/dog";

        //Dog.class 返回类型
        return restTemplate.getForObject(addr+api, Dog.class);
//        return new Dog("didi", 11);
    }
}

 

 

三、Feign负载均衡

前面的可以发现当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻

 

Feign是以接口方式进行调用,而不是通过RestTemplate来调用,feign底层还是ribbon,它进行了封装

 

3.1、common模块(声明接口)

1)添加依赖

<!--Eureka服务端支持-->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
      <version>2.2.3.RELEASE</version>
    </dependency>

 

2)创建接口(该接口不需要实现)

package org.example.feignconsumer.service;


import org.example.domain.Dog;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

//@FeignClient注解表示当前接口和一个Provider对应,注解value属性指定要调用的Provider微服务名称
@FeignClient(value = "provider01")
public interface DogService {
    //远程调用的接口方法
    //要求@RequestMapping注解映射的地址一致
    //要求方法声明一致
    //用来获取请求参数的@RequestParam 、 @PathVariable 、@RequestBody不能省略,要两边一致
    @RequestMapping(value = "/dog")
    public Dog getDog();
}

 

 

3.2、provider(提供服务)

1)添加依赖

        <!--Eureka服务端支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

 

2)配置

server.port=7000


spring.application.name=provider01

eureka.client.service-url.defaultZone=http://localhost:5000/eureka

 

3)controller

package com.example.provider.web;


import org.example.domain.Dog;
import org.springframework.http.HttpRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

@RestController
public class DogController {

//    @RequestMapping(value = "/dog",produces = "application/json;charset=utf-8")
//    public Dog getDog(HttpServletRequest request){
//
//        int serverPort = request.getServerPort();
//
//        return new Dog("肥松 "+serverPort, 2);
//    }


    @RequestMapping(value = "/dog")  //要与service中的方法保持一致
    public Dog getDog(){

        return new Dog("肥松", 2);
    }

}

 

 3.3、consumer(消费服务)

1)添加依赖

    <dependency>
            <groupId>org.example</groupId>
            <artifactId>common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <!--Eureka服务端支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>

 

2)配置

server.servlet.context-path=/consumer

spring.application.name=consumer01

eureka.client.serviceUrl.defaultZone=http://localhost:5000/eureka

 

3)controller

package org.example.feignconsumer.controller;


import org.example.domain.Dog;
import org.example.feignconsumer.service.DogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    //需保证包与common一致(org.example.feignconsumer),否则找不到service
    @Autowired
    private DogService dogService;
    
    @RequestMapping("/test")
    public Dog test01(){
        return dogService.getDog();
    }

}

 

4)主启动类添加注解

@EnableFeignClients

 

四、Hystrix熔断

4.1、熔断(provider端措施)

1)在provider加入依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>

 

2)在provider主启动类加入注解

//开启断路器功能
@EnableCircuitBreaker

 

3)修改controller

package com.example.provider.web;


import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.example.domain.Dog;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class DogController {

    @HystrixCommand(fallbackMethod = "getDogBackup")
    @RequestMapping(value = "/dog")
    public Dog getDog(@RequestParam("signal") String signal) throws InterruptedException {
        if("bang".equals(signal))
            throw new RuntimeException();
        if ("sleep".equals(signal))
            Thread.sleep(5000);

        return new Dog("肥松", 2);
    }


    //当发生故障时。执行此方法返回
    public Dog getDogBackup(@RequestParam("signal") String signal){
        return new Dog(signal, 0);
    }

}

 

4.2、降级(consumer端措施)

服务降级处理是在客户端(consumer端)实现完成的,与服务端(provider)无关,当某个consumer访问一个provider却迟迟得不到响应时,执行预先设定好的一个解决方案,而不是一直等待。

实现步骤:

1)common中添加依赖

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
      <version>2.2.3.RELEASE</version>
    </dependency>

 

2)common中创建factory类

package org.example.feignconsumer.factory;

import feign.hystrix.FallbackFactory;
import org.example.domain.Dog;
import org.example.feignconsumer.service.DogService;
import org.springframework.stereotype.Component;


/**
 * 1.实现consumer端服务降级功能
 * 2.实现FallbackFactory接口时要传入@FeignClient注解标记的接口类型
 * 3.在create方法中返回的@FeignClient注解标记的接口类型的对象,当provider调用失败后,会执行这个对象的对应方法
 */

@Component
public class MyFallBackFactory implements FallbackFactory<DogService> {
    @Override
    public DogService create(Throwable throwable) {
        return new DogService() {
            @Override
            public Dog getDog(String signal) {
                return new Dog("降级:"+throwable.getMessage(), 10);
            }
        };
    }
}

 

3)consumer配置添加

feign.hystrix.enabled=true

 

4)common中service添加注解

//@FeignClient注解表示当前接口和一个Provider对应,注解value属性指定要调用的Provider微服务名称
@FeignClient(value = "provider01", fallbackFactory = MyFallBackFactory.class)
public interface DogService {

 

 

五、hystrix监控

5.1、provider端

1)添加依赖

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

 

2)添加配置

management.endpoints.web.exposure.include=hystrix.stream

 

 

5.2、新建dashboard工程

1)添加依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>

 

2)主启动类添加注解

@EnableHystrixDashboard

 

3)配置

server.port=8000

spring.application.name=dashboard

 

4)登录

http://localhost:8000/hystrix

 

 

六、ZUUL网关

 

 

6.1、使用zuul

1)创建zuul工程

 

2)添加依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>

 

3)配置

server.port=9000

spring.application.name=zuul

eureka.client.serviceUrl.defaultZone=http://localhost:5000/eureka

 

4)添加注解

//启用zuul代理
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication 

 

5)访问

 

 

6.2、其他配置

1)使用指定地址代替微服务名称

 

 

2)让用户不能通过微服务名称访问

 

 

3)给访问路径加统一前缀

 

 

6.3、zuulfilter

package org.example.gateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class MyZuulFilter extends ZuulFilter {


    /**
     * 返回过滤器类型
     * pre表示在目标微服务前执行
     * @return
     */
    @Override
    public String filterType() {
        String type = "pre";
        return type;
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 判断当前请求是否要进行过滤
     * 要过滤:返回true,继续执行run方法
     * 不过滤:返回false,直接放行
     * @return
     */
    @Override
    public boolean shouldFilter() {
        //获取request对象
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        String signal = request.getParameter("signal");

        return signal.equals("bang");
    }

    @Override
    public Object run() throws ZuulException {
        System.out.println("run方法执行了。。。。。。。。。。");
        //当前实现忽略这个方法的返回值,所以返回null,不做特殊处理
        return null;
    }
}

 

七、SpringCloudAlibaba实战案例

项目结构:

 

 

 

7.1、注册中心

7.1.1、运行Nacos注册中心

1、Nacos下载和安装

 

2、Windows启动Nacos

解压:将下载的压缩包解压

 

启动:startup.cmd -m standalone

 

3、访问

http://localhost:8848/nacos

用户名密码:nacos/nacos

 

7.1.2、服务发现

1、引入依赖

service-base模块中配置Nacos客户端依赖
<!--服务发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2、添加服务配置信息

在需要注册到注册中心的微服务放入配置文件中添加配置
#spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos服务地址

3、启动微服务

启动已注册的微服务,查看 “服务管理 => 服务列表”,可就以看到已注册的微服务

 

 

 

7.2、OpenFeign

需求

发送短信时校验手机号是否注册

7.2.1、校验手机号是否注册

1、UserInfoController

service-core中添加controller方法:检查手机号码是否已经注册账号
@ApiOperation("校验手机号是否注册")
@GetMapping("/checkMobile/{mobile}")
public boolean checkMobile(@PathVariable String mobile){
    return userInfoService.checkMobile(mobile);
}

2、UserInfoService

接口:
boolean checkMobile(String mobile);

实现:

@Override
public boolean checkMobile(String mobile) {
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("mobile", mobile);
    Integer count = baseMapper.selectCount(queryWrapper);
    return count > 0;
}

 

7.2.2、OpenFeign的引入

1、引入依赖

service-base模块中配置OpenFeign的依赖(实际是在服务消费者端需要OpenFeign的依赖)
<!--服务调用-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2、启动类添加注解

在service-sms的启动类添加如下注解
@EnableFeignClients

 

7.2.3、接口的远程调用

service-sms中添加远程调用

1、CoreUserInfoClient

接口:
@FeignClient(value = "service-core")
public interface CoreUserInfoClient {

    @GetMapping("/api/core/userInfo/checkMobile/{mobile}")
    boolean checkMobile(@PathVariable String mobile);
}

 

2、ApiSmsController

引入client
@Resource
private CoreUserInfoClient coreUserInfoClient;

在获取验证码方法中调用远程方法校验手机号是否存在

//手机号是否注册
boolean result = coreUserInfoClient.checkMobile(mobile);
System.out.println("result = " + result);
Assert.isTrue(result == false, ResponseEnum.MOBILE_EXIST_ERROR);

//生成验证码
.....

 

7.2.4、超时控制

openfeign默认的连接超时时间为1秒,测试时很可能会出现远程调用超时错误。
可以在配置文件中添加如下配置:
feign:
  client:
    config:
      default:
        connectTimeout: 10000 #连接超时配置
        readTimeout: 600000 #执行超时配置

 

7.2.5、OpenFeign日志

1、作用

OpenFeign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解OpenFeign中Http请求的细节。即对OpenFeign远程接口调用的情况进行监控和日志输出。

2、日志级别

  • NONE:默认级别,不显示日志
  • BASIC:仅记录请求方法、URL、响应状态及执行时间
  • HEADERS:除了BASIC中定义的信息之外,还有请求和响应头信息
  • FULL:除了HEADERS中定义的信息之外,还有请求和响应正文及元数据信息
 

3、配置日志bean

在service-base中创建配置文件
@Configuration
public class OpenFeignConfig {

    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}

 

4、开启日志

sms的application.yml中指定监控的接口,以及日志级别
logging:
  level:
    com.atguigu.srb.sms.client.CoreUserInfoClient: DEBUG #以什么级别监控哪个接口

 

5、修改logback日志级别

修改日志的level为DEBUG
<!-- 开发环境和测试环境 -->
<springProfile name="dev,test">
    <logger name="com.example" level="DEBUG">
        <appender-ref ref="CONSOLE" />
    </logger>
</springProfile>

 

6、查看日志输出

补充:
HTTP 是一种无状态协议,客户端向服务器发送一个 TCP 请求,服务端响应完毕后断开连接。
如果客户端向服务器发送多个请求,每个请求都要建立各自独立的连接以传输数据。
HTTP 有一个 KeepAlive 模式,它告诉 webserver 在处理完一个请求后保持这个 TCP 连接的打开状态。
若接收到来自客户端的其它请求,服务端会利用这个未被关闭的连接,而不需要再建立一个连接。
KeepAlive 在一段时间内保持打开状态,它们会在这段时间内占用资源。占用过多就会影响性能。
timeout 来指定 KeepAlive 的超时时间(timeout)。指定每个 TCP 连接最多可以保持多长时间。
 

7.3、Sentinel熔断

1、service-base中引入sentinel依赖

<!--服务容错-->
<dependency>
    <groupId>com.alibaba.cloud</groupId> 
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

 

2、开启Sentinel支持

在service-sms的yml配置文件中开启Feign对Sentinel的支持
#开启Feign对Sentinel的支持
#feign:
  sentinel:
    enabled: true

 

3、创建容错类(降级方式)

fallback:当无法校验手机号是否已注册时,直接发送短信
@Service
@Slf4j
public class CoreUserInfoClientFallback implements CoreUserInfoClient {
    @Override
    public boolean checkMobile(String mobile) {
        log.error("远程调用失败,服务熔断");
        return false;
    }
}

 

4、指定熔断类

为OpenFeign远程调用接口添加fallback属性值没指定容错类
@FeignClient(value = "service-core", fallback = CoreUserInfoClientFallback.class)
public interface CoreUserInfoClient {

 

7.4、网关

不使用网关时:

 

 

使用网关时:

 

 

 

7.4.1、创建模块service-gateway

1、创建模块

在srb下创建普通maven模块
Artifact:service-gateway
 

2、配置pom

在service-gateway的pom中添加如下依赖
<dependencies>
    <!-- 网关 -->
    <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>
</dependencies>

 

3、配置application.yml

server:
  port: 80 # 服务端口

spring:
  profiles:
    active: dev # 环境设置
  application:
    name: service-gateway # 服务名
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos服务地址
    gateway:
      discovery:
        locator:
          enabled: true # gateway可以发现nacos中的微服务,并自动生成转发路由

 

4、logback.xml

修改日志输出目录名为 gateway
 

5、创建启动类

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceGatewayApplication.class, args);
    }
}

 

6、启动网关

注意:因为nginx和网关同时使用了80端口,因此先停止nginx,然后再启动网关
nginx.exe -s stop

 

7、测试自动路由转发

规则:
http://Gateway_HOST:Gateway_PORT/serviceId/**
 

7.4.2、路由配置

1、基本配置

application.yml文件中添加路由配置
#spring:
# cloud:
#   gateway:
      routes:
      - id: service-core
        uri: lb://service-core   #lb负载均衡,当有多个相同service采用默认轮询访问
        predicates:
        - Path=/*/core/**        #当访问路径有core时自动找到service-core服务,这样访问路径就可以去掉service-core
      - id: service-sms
        uri: lb://service-sms
        predicates:
        - Path=/*/sms/**
      - id: service-oss
        uri: lb://service-oss
        predicates:
        - Path=/*/oss/**

2、测试路由转发

 
 

7.4.3、跨域配置

1、配置文件

在 service-gateway中添加跨域配置
@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); //是否允许携带cookie
        config.addAllowedOrigin("*"); //可接受的域,是一个具体域名或者*(代表任意域名)
        config.addAllowedHeader("*"); //允许携带的头
        config.addAllowedMethod("*"); //允许访问的方式

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

2、删除后端跨域配置

删除微服务中的跨域注解 @CrossOrigin