书接上回,接续放文件

bootstram.yml

application.yamlapplication.yamleureka:
  instance:
    hostname: userservice
    prefer-ip-address: true
    instance-id: userservice
  client:
    service-url:
      defaultZone: http://47.116.120.170:8763/eureka/,http://47.116.120.170:8762/eureka/,http://47.116.120.170:8761/eureka/
spring:
  bus:
    enabled: true
    refresh:
      enabled: true
  rabbitmq:
    host: 122.51.93.221
    port: 5672
    username: guest
    password: hbb_62791276
  cloud:
    config:
      profile: dev        # 不加此属性直接获取eureka-client.yml,加了后符合config的名字规则eureka-client-dev.yml
      enabled: true
      name: config-eureka-client   # 配置中心Git仓库config文件夹里的文件名字
      label: master         # git的默认分支master
      fail-fast: true       # 是否启动快速失败功能,功能开启则优先判断config server是否正常
      discovery:
        enabled: true            #启动配置中心发现服务
        service-id: config-server
      #      allow-override: true  # 允许被覆盖,如果是配置文件,则不允许被覆盖
      #      override-none: false  #远程配置不覆盖任何本地配置
      #      override-system-properties: false  #远程配置不覆盖系统属性与环境变量,但是会覆盖本地配置文件
      retry:
        # 配置重试次数,默认为6
        max-attempts: 3
        # 间隔乘数,默认1.1
        multiplier: 1
        # 初始重试间隔时间,默认1000ms
        initial-interval: 1000
        # 最大间隔时间,默认2000ms
        max-interval: 3000

application.yaml

spring:
  application:
    name: userservice
management:
  endpoint:
    shutdown:
      enabled: false
  endpoints:
    web:
      exposure:
        include: busrefresh

application.properties

package com.binson.userservice.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * ClassName: GitAutoRefreshConfig
 * Description:
 *
 * @author binbin_hao
 * @date 2024/9/11 15:20
 */
@Component
@Data
@Configuration
@ConfigurationProperties(prefix = "data")
public class GitAutoRefreshConfig {
    public static class UserInfo {
        private String username;

        private String password;

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        @Override
        public String toString() {
            return "UserInfo{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }

    private String env;

    private UserInfo user;
}
# 应用服务 WEB 访问端口
server.port=18895

java类

package com.binson.userservice.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * ClassName: GitAutoRefreshConfig
 * Description:
 *
 * @author binbin_hao
 * @date 2024/9/11 15:20
 */
@Component
@Data
@Configuration
@ConfigurationProperties(prefix = "data")
public class GitAutoRefreshConfig {
    public static class UserInfo {
        private String username;

        private String password;

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        @Override
        public String toString() {
            return "UserInfo{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }

    private String env;

    private UserInfo user;
}

类2

package com.binson.userservice.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * ClassName: GiteeConfig
 * Description:
 *
 * @author binbin_hao
 * @date 2024/9/11 15:17
 */
@Data
@Component
public class GiteeConfig {
    @Value("${data.env}")
    private String env;

    @Value("${data.user.username}")
    private String username;

    @Value("${data.user.password}")
    private String password;
}

类3

package com.binson.userservice.controller;

import com.binson.openfegin.clients.UserServiceClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * ClassName: OrderController
 * Description:
 *
 * @author binbin_hao
 * @date 2024/9/10 14:15
 */
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private UserServiceClient userServiceClient;
    @Autowired
    @RequestMapping("/get")
    public String hello()
    {

        return userServiceClient.helloOrder();
    }
}

类4

package com.binson.userservice.controller;

import com.binson.openfegin.clients.UserServiceClient;
import com.binson.pojo.entry.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * ClassName: UserController
 * Description:
 *
 * @author binbin_hao
 * @date 2024/9/10 14:01
 */
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserServiceClient userServiceClient;
    @GetMapping("/get")
    public User hello(@RequestParam(value = "userId") String userId)
    {
        return userServiceClient.getUser("1");
    }
}

来不解释,里面有些参数可能在后面会使用比如bus,config, 你现整上,咱们先结婚后谈感情。

5.接下来是gateway

gateway 能干啥呢,不是明明都有nginx 了,你说要他有何用?

接下来我就放一个ai 告诉我的答案:

尽管 Nginx 和 Gateway(在微服务架构中常指API Gateway)在功能上有所重叠,尤其是它们都可以处理HTTP请求、路由和负载均衡,但它们各自的设计和用途有所不同,因此它们可以并存,并在不同的场景下发挥各自的优势。

Nginx 的主要作用:

  1. 高性能的Web服务器和反向代理:Nginx以其高性能著称,能够处理大量的并发连接。它经常被用作Web服务器,或者作为反向代理来将请求转发到后端的Web应用服务器。

  2. 负载均衡:Nginx可以基于多种策略(如轮询、最少连接、IP哈希等)将请求分发到后端多个服务器上,以实现负载均衡。

  3. 静态文件服务:Nginx可以高效地提供静态文件服务,如图片、视频、JavaScript、CSS等。

  4. SSL/TLS终止:Nginx可以作为SSL/TLS的终结点,处理HTTPS请求,从而减轻后端服务器的SSL/TLS处理负担。

API Gateway 的主要作用:

  1. 服务聚合:在微服务架构中,API Gateway可以将多个微服务的API聚合成一个统一的API接口,客户端只需要与API Gateway交互即可。

  2. 认证和授权:API Gateway可以作为所有请求的入口点,执行认证和授权逻辑,确保只有合法用户才能访问特定的服务。

  3. 限流和熔断:为了保护后端服务不被大量请求压垮,API Gateway可以实现限流策略,并在必要时熔断,阻止更多的请求到达后端。

  4. 协议转换:API Gateway可以将不同微服务之间的通信协议进行转换,实现异构系统之间的通信。

  5. 监控和日志:作为所有请求的入口点,API Gateway可以收集请求和响应数据,用于监控和日志记录。

为什么两者可以并存:

  • 性能考虑:Nginx的高性能使其成为处理静态文件和大量并发HTTP请求的理想选择。而API Gateway则更侧重于服务聚合、认证授权等高级功能。

  • 架构灵活性:在微服务架构中,将Nginx作为反向代理和负载均衡器,而将API Gateway作为微服务的前端入口,可以使得整个系统更加灵活和可扩展。

  • 安全和管理:API Gateway提供的认证授权、限流熔断等功能,可以增强系统的安全性和可管理性,而Nginx则更专注于性能优化和静态文件服务。

因此,尽管Nginx和API Gateway在某些功能上有所重叠,但它们在微服务架构中各自扮演着不可替代的角色,可以共存并互补。

看不懂没关系,你跟TA相处久了就知道他俩深浅不一样。

话不多说先放截图:

放文件:

pom文件:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.binson</groupId>
    <artifactId>gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
        <spring-cloud.version>2021.0.5</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.sun.jersey</groupId>
                    <artifactId>jersey-client</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jersey</groupId>
                    <artifactId>jersey-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jersey.contribs</groupId>
                    <artifactId>jersey-apache-client4</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--集成redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.4.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <!--            <version>2.9.0</version>-->
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.binson.gateway.GatewayApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

对应类:

package com.binson.gateway.filter.factories;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import java.util.List;
import java.util.function.Predicate;

/**
 * ClassName: MyCommonGateWayFilterFactory
 * Description:
 *
 * @author binbin_hao
 * @date 2024/9/9 14:54
 */
@Slf4j
@Component("MyCommonGateWayFilterFactory")
public class MyCommonGateWayFilterFactory extends AbstractGatewayFilterFactory<MyCommonGateWayFilterFactory.Config> {

    public MyCommonGateWayFilterFactory() {
        super(Config.class);
        log.info("Loaded GatewayFilterFactory [Authorize]");
    }

    @Override
    public GatewayFilter apply(Config config) {
        String require=config.getRequire();
        List<String> allow=config.getAllow();
        Predicate<ServerWebExchange> isAllowedPath = exchange -> {
            String path = exchange.getRequest().getURI().getPath();
            return allow.stream().anyMatch(allowedPath -> path.startsWith(allowedPath));
        };
        return (exchange, chain) -> {
            String path=exchange.getRequest().getURI().getPath();
            if (!isAllowedPath.test(exchange)){
                return chain.filter(exchange);
            }
            String token=exchange.getRequest().getQueryParams().getFirst("Authorization");
            if (StringUtils.isEmpty(token) || validateToken(token,require)){
                ServerHttpResponse status = exchange.getResponse();
                status.setStatusCode(HttpStatus.UNAUTHORIZED);
                return status.setComplete();
            }
            return chain.filter(exchange);
        };
    }

    private boolean validateToken(String token, String require) {
        //这里面只做简单的校验,实际开发中,需要根据业务来判断是否合法
        if (require.equals(token)){
            return false;
        }else {
            return true;
        }
    }


    public static class Config {
        private String require;
        private List<String> allow;

        public String getRequire() {
            return require;
        }

        public void setRequire(String require) {
            this.require = require;
        }
        public List<String> getAllow() {
            return allow;
        }
        public void setAllow(List<String> allow) {
            this.allow = allow;
        }
    }
}

启动类

package com.binson.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {

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

}

重头戏配置:

路由配置有两种方式,一种是配置文件配置,一种是代码配置,看个人习惯

application.yml

server:
  port: 8861
spring:
  application:
    name: gateway
#  redis:
#    host: 123.57.89.158
#    port: 6380
#    password: xxxx
#    pool:
#      max-active: 100
#      max-wait: -1
#      max-idle: 8
#    timeout: 30000

  cloud:
    gateway:
      discovery:
        locator:
          enabled: true

      routes:
        - id: service-a
          uri: lb://userservice/
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1
            - name: MyCommonGateWayFilterFactory
              args:
                require: "someVaue"
                allow: ["a", "b"]
        - id: service-b
          uri: lb://userservice/
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=1

eureka:
  instance:
    instance-id: gatewayService
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 1
    lease-expiration-duration-in-seconds: 3
    hostname: gatewayService
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://47.116.121.171:8763/eureka/,http://47.116.121.171:8762/eureka/,http://47.116.121.171:8761/eureka/

这里面具体参数都是什么意思,你后面研究,不过提醒一点 因为咱们是路由的地址是服务发现,所以 uri: lb://userservice/ ,这个其实是服务发现里面对应的服务id。如果有别的服务,你也可以按照这个方式整。

接下来你将看到这个:

这里面的配置信息是从配置中心读取的,这就引入我们接下来说的配置中心config跟消息总线bus.

6配置中心config以及消息总线bus

先说明一点,消息总线可不只是能够帮忙动态把配置信息同步到所有服务中这么简单,但这是你能用到的最有用的地方。

因为如果你仅仅是用了配置中心,那么配置中心里面的配置内容你更改后,如果项目的实例服务比较到你一个一个更新显然是不科学的,

我们就用到消息总线bus+rabbitmq 的消息同步,让一个地方刷新,所有的服务都跟着刷新配置信息,这配置中心不就完美的实现了动态配置更新了吗?

第一步我们的先整一个config server ,这个server 能去git 上面读取配置内容,然后其他config client 才能从server 端读取配置信息。

那么我们就先去git 上面声明几个配置文件:

里面内容大概就是这样:

废话不多说config 服务端截图开始:

pom文件:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.binson</groupId>
    <artifactId>eurekaserver</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eurekaserver</name>
    <description>eurekaServer</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
        <spring-cloud.version>2021.0.5</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.binson.eurekaserver.EurekaserverApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

application.yaml

#https://gitee.com/vbinson/config/blob/master/config.json
server:
  port: 3302
spring:
  application:
    name: config-server
  cloud:
    bus:
      id: ${spring.application.name}:${server.port}:*
      enabled: true
      refresh:
        enabled: true
    config:
      retry:
        initial-interval: 5000
        max-interval: 60000
        multiplier: 1.5
        max-attempts: 5
      server:
        git:
          uri: https://gitee.com/vbinson/config.git
          username: isom@vip.qq.com
          password: password
          default-label: master
          force-pull: true
  rabbitmq:
    host: 122.51.92.221
    port: 5672
    username: guest
    password: password

eureka:
  instance:
    instance-id: config-server
    prefer-ip-address: true
    hostname: config-server
  client:
    service-url:
      defaultZone: http://47.116.120.170:8763/eureka/,http://47.116.120.170:8762/eureka/,http://47.116.120.170:8761/eureka/

management:
  endpoint:
    shutdown:
      enabled: false
  endpoints:
    web:
      exposure:
        include: busrefresh

没事可以关注一下我的gitee 账号 vbinson

配置的server 配置完了,也能正常读取配置信息了,读取配置信息的规则:

/{application}/{profile}[/{label}]

/{application}-{profile}.yml

/{label}/{application}-{profile}.yml

/{application}-{profile}.properties

/{label}/{application}-{profile}.properties

不理解没关系,我放一个实际的显示效果吧:

http://localhost:3302/config-eureka-client/dev/master

因为这里面顺带把bus 也给加进去了。

如果你改了配置文件,怎么看有没有把整个服务都更新了呢?

接下来我们开始演示:

第一步没有更新的情况:

接下来我改一下配置:

我不更新的话展示的效果:

显然是没有变化。接下来开始上道具:

记得一定要post请求!!!!!

接下来在请求:嘿,你看变了。刷新咱们使用config server 来请求刷新,调用服务的时候发现信息同步了!

rabbitmq的截图:

刷新的时候,这些配置rabbitmq 的服务显然都已经在处理更新了。

有点遗憾是里面好多东西没来的细讲,我给你将不如你自己查,咱们这里就基本上只上代码跟效果。剩下的你自己悟吧!