美文网首页
微服务 Spring Cloud Alibaba 项目搭建(五、

微服务 Spring Cloud Alibaba 项目搭建(五、

作者: 一介书生独醉江湖 | 来源:发表于2023-07-26 17:33 被阅读0次

一、gateway 网关子模块创建

1、右键项目 - New - Module

image.png

2、bootstrap.yml

server:
  port: 8008
  servlet:
    context-path:
  tomcat:
    uri-encoding: utf-8
spring:
  application:
    name: gateway   #唯一名称
  profiles:
    active: dev           # 运行环境
  freemarker:
    check-template-location: false
    prefer-file-system-access: false
logging:      # logback 配置
  path: /usr/local/alibaba/logs/${spring.application.name}   # 保存日志文件目录路径
  level: # 日志级别
    org.springframework.web: DEBUG # 配置spring web日志级别

3、bootstrap-dev.yml

spring:
  cloud:
    sentinel:
      transport:
        port: 8719                                     # 默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        dashboard: 127.0.0.1:9090                    # [sentinel]管理控制台地址
      eager: true
    nacos:
      discovery:
        server-addr: 192.168.0.119:8848                  # [nacos]的访问地址,根据上面准备工作中启动的实例配置
        namespace: 11ba48cc-9931-4760-bf58-7d3e2c99629c   # [nacos]test命名空间的ID
      config:
        server-addr: 192.168.0.119:8848                  # [nacos]的访问地址,根据上面准备工作中启动的实例配置
        namespace: 11ba48cc-9931-4760-bf58-7d3e2c99629c   # [nacos]test命名空间的ID
        group: DEFAULT_GROUP                              # [nacos]默认分组就是DEFAULT_GROUP,如果使用默认分组可以不配置
        file-extension: yml                               # [nacos]默认properties
    gateway:
      locator:
        enabled: true                 # 让gateway可以发现nacos中的微服务
      globalcors:                     # 网关cors跨域设置
        cors-configurations:
          '[/**]':                    # gateway网关上所有的uri都应用下面的跨域设置
            allowed-credentials: true # 允许携带认证信息
            allowed-origins:
              - "*"                   # 允许所有来源进行跨域访问
            allowed-headers: "*"      # 允许跨域请求里的head字段,设置为*是全部
            allowed-methods:          # 允许跨域的方法
              - GET
              - POST
              - PUT
              - DELETE
              - OPTIONS
            max-age: 3600
      routes:
        # oauth
        - id: oauth             # 当前路由的标识, 要求唯一
          uri: lb://oauth       # lb指的是从 nacos 中按照名称获取微服务,并遵循负载均衡策略
          predicates: # 断言(就是路由转发要满足的条件)
            - Path=/oauth/**    # 当请求路径满足Path指定的规则时,才进行路由转发
        # api
        - id: api               # 我们⾃定义的路由 ID,保持唯⼀
          uri: lb://api         # ⽬标服务地址(部署多实例)
          # gateway⽹关从服务注册中⼼获取实例信息然后负载后路由
          # 断⾔:路由条件,Predicate 接受⼀个输⼊参数,返回⼀个布尔值结果。该接⼝包含多种默认⽅法来将 Predicate 组合成其他复杂的逻辑(⽐如:与,或,⾮)。
          predicates:
            - Path=/api/**
          #filters: # 过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
          #  - StripPrefix=1    # 转发之前去掉1层路径
        # miniapp-oauth
        - id: miniapp-oauth
          uri: lb://miniapp-oauth
          predicates:
            - Path=/miniapp-oauth/**
        # miniapp-api
        - id: miniapp-api
          uri: lb://miniapp-api
          predicates:
            - Path=/miniapp-api/**
          #filters:
          #  - StripPrefix=1
        # callback
        - id: callback
          uri: lb://callback
          predicates:
            - Path=/callback/**
          #filters:
          #  - StripPrefix=1

4、pom.xml

<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>
        <groupId>com.aydan</groupId>
        <artifactId>ali-cloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>gateway</artifactId>
    <packaging>jar</packaging>

    <name>gateway</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
        </dependency>

        <!--GateWay 网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--引入webflux-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <!-- Actuator可以帮助你监控和管理Spring Boot应⽤-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--nacos config client 依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--链路追踪-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>

        <!-- SpringCloud Alibaba Sentinel 流量监控控制台 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- SpringCloud Alibaba Sentinel 网关限流 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
        </dependency>
      <!-- SpringCloud Alibaba Sentinel 持久化 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!--编译插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
            <!--打包插件-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

5、GatewayApplication.java

package com.aydan;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.TimeZone;

/**
 * @Author ds
 * @Date 2023/7/27
 */
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
        ConfigurableApplicationContext application = SpringApplication.run(GatewayApplication.class, args);
        Environment environment = application.getEnvironment();
        String applicationName = environment.getProperty("spring.application.name");
        String port = environment.getProperty("server.port");
        String contextPath = environment.getProperty("server.servlet.context-path");
        System.out.println("---------------------------------------------------------->");
        System.out.println(" :: ServletInitializer 启动:" + applicationName);
        String localHost;
        try {
            localHost = InetAddress.getLocalHost().getHostAddress();
            System.out.println("\t\t http://" + localHost + ":" + port + "" + contextPath + "");
            System.out.println("\t\t http://127.0.0.1:9090");
        } catch (UnknownHostException e) {
            System.out.println("\t\t " + e.getMessage());
            e.printStackTrace();
        }
        System.out.println("<----------------------------------------------------------");
    }

}

6、CorsConfig.java

package com.aydan.config;

import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

/**
 * @Author ds
 * @Date 2023/7/27
 */
@Component
public class CorsConfig {

    @Bean
    public CorsWebFilter corsWebFilter() {

        /**
         * 返回一个CorsWebFilter ,构造其中需要传入连个形参,均为接口,可以直接new 接口
         * 是借口可以使用它的实现类来处理
         */
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();

        //构建CorsConfiguration
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedMethod(HttpMethod.DELETE);
        corsConfiguration.addAllowedMethod(HttpMethod.PUT);
        corsConfiguration.addAllowedMethod(HttpMethod.OPTIONS);
        corsConfiguration.addAllowedMethod(HttpMethod.GET);
        corsConfiguration.addAllowedMethod(HttpMethod.POST);
        corsConfiguration.addAllowedMethod(HttpMethod.HEAD);
        corsConfiguration.addAllowedHeader("*");
        // 允许cookie跨域
        corsConfiguration.setAllowCredentials(true);

        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsWebFilter(urlBasedCorsConfigurationSource);
    }

}

7、GatewayConfig.java

package com.aydan.config;

import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.aydan.core.BaseResponse;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Author ds
 * @Date 2023/7/27
 */
@Configuration
public class GatewayConfig {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfig(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolvers;
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    /**
     * 初始化一个限流的过滤器
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }


    /**
     * 配置初始化的限流参数
     */
    @PostConstruct
    public void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        // 分别给指定的资源 配置限流
        // GatewayFlowRule 资源名称,对应路由id     setCount  限流阈值   setIntervalSec 统计时间窗口,单位是秒,默认是 1 秒
        // 简单来说就是     如果Count=1    IntervalSec=1  那么一秒钟只允许访问一次   (用于测试)
        // 如果Count=5    IntervalSec=2  那么2秒钟只允许访问5次   (用于测试)
        // 如果Count=60   IntervalSec=3  那么3秒钟只允许访问60次 也就是1秒20次  一般用于生产(一般够了)
        // 如果是商城网站那么Count和IntervalSec 这个需要计算平均每天每秒最大的请求量是多少然后在设置
        int count = 50;
        int intervalSec = 5;

        // 设置指定路由的限流
        rules.add(new GatewayFlowRule("api").setCount(count).setIntervalSec(intervalSec));
        rules.add(new GatewayFlowRule("miniapp-api").setCount(count).setIntervalSec(intervalSec));

        GatewayRuleManager.loadRules(rules);

    }


    /**
     * 配置限流的异常处理器
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    /**
     * 自定义限流异常页面
     */
    @PostConstruct
    public void initBlockHandlers() {
        BlockRequestHandler blockRequestHandler = (serverWebExchange, throwable) -> {
            BaseResponse response = new BaseResponse();
            response.setStatus(429);
            response.setMessage("请求过于频繁");
            return ServerResponse.status(HttpStatus.OK).
                    contentType(MediaType.APPLICATION_JSON_UTF8).
                    body(BodyInserters.fromObject(response));
        };
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }
}

8、BaseResponse.java

package com.aydan.core;

import lombok.Data;

import java.io.Serializable;

/**
 * @Author ds
 * @Date 2023/7/27
 */
@Data
public class BaseResponse implements Serializable {

    private static final long serialVersionUID = 1L;

    protected int status;
    protected String message;
    protected String recvTime;
    protected String respTime;
}

9、Nacos配置

image.png
image.png
参考:
https://www.jianshu.com/p/552416053ff1

相关文章

网友评论

      本文标题:微服务 Spring Cloud Alibaba 项目搭建(五、

      本文链接:https://www.haomeiwen.com/subject/ptdkpdtx.html