Microservice-Gateway

Case building

Official website address

Insert image description here
Parent Pom

<com.alibaba.cloud.version>2.2.8.RELEASE</com.alibaba.cloud.version>
<com.cloud.version>Hoxton.SR12</com.cloud.version>
<com.dubbo.version>2.2.7.RELEASE</com.dubbo.version>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${com.alibaba.cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${com.cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-dubbo -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
            <version>${com.dubbo.version}</version>
        </dependency>
    </dependencies>

</dependencyManagement>

Engineering POM

<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: 9005
spring :
  application:
    name: gateway-server
  cloud:
    nacos:
      discovery:
        server-addr: ip:8848
    gateway:
      routes:
        - id: gateway-provider
          uri: http://127.0.0.1:8088
          predicates:
            - Path=/provider/**
          filters:
            - StripPrefix=1
        - id: gateway-consumer
          uri: http://127.0.0.1:8089
          predicates:
            - Path=/consumer/** 
          filters:
            - StripPrefix=1 #转发之前将路径前面的一个字符串去除 比如/consumer/echo  最终转发到服务是 http://127.0.0.1:8089/echo
        - id: gateway-lb
          uri: lb://openfeign-provider #负载均衡,填写nacos里面的服务名称
          predicates:
            - Path=/lb/**
          filters:
            - StripPrefix=1

Start an ordinary server and consumer, and set up a cluster with three services. It is relatively easy to set up these nodes. You can see the notes in the same directory.
How to achieve load balancing? How to explore the source code to find the load balancer?
org.springframework.cloud.gateway.filter.LoadBalancerClientFilter

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
		URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
		String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
		if (url == null
				|| (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
    
    
			return chain.filter(exchange);
		}
		// preserve the original url
		addOriginalRequestUrl(exchange, url);

		if (log.isTraceEnabled()) {
    
    
			log.trace("LoadBalancerClientFilter url before: " + url);
		}
		// 选择实例
		final ServiceInstance instance = choose(exchange);

		if (instance == null) {
    
    
			throw NotFoundException.create(properties.isUse404(),
					"Unable to find instance for " + url.getHost());
		}

		URI uri = exchange.getRequest().getURI();

		// if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
		// if the loadbalancer doesn't provide one.
		String overrideScheme = instance.isSecure() ? "https" : "http";
		if (schemePrefix != null) {
    
    
			overrideScheme = url.getScheme();
		}
		// 选择好节点以后重新组织请求URI
		URI requestUrl = loadBalancer.reconstructURI(
				new DelegatingServiceInstance(instance, overrideScheme), uri);

		if (log.isTraceEnabled()) {
    
    
			log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
		}

		exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
		return chain.filter(exchange);
	}

Custom interception

First, let’s look at the several assertions provided by the official website. They are all relatively simple and will not be demonstrated here:
official website address
source code. These classes provide these capabilities:
Insert image description here
custom local
custom class. This class can be defined with reference to DedupeResponseHeaderGatewayFilterFactory.

@Component
public class CostGatewayFilterFactory extends
        AbstractGatewayFilterFactory<CostGatewayFilterFactory.CustomConfig> {
    
    
    public CostGatewayFilterFactory() {
    
    
        super(CustomConfig.class);
    }
    @Override
    public List<String> shortcutFieldOrder() {
    
    
       return Arrays.asList("switchStatus");
    }
    @Override
    public GatewayFilter apply(CostGatewayFilterFactory.CustomConfig config) {
    
    
        return new GatewayFilter() {
    
    

            @Override
            public Mono<Void> filter(ServerWebExchange exchange,
                                     GatewayFilterChain chain) {
    
    
                if (!config.switchStatus.equalsIgnoreCase("on")) {
    
    
                    // 如果这个开关是关闭状态
                   return chain.filter(exchange);
                }
                long sTime = System.currentTimeMillis();
                exchange.getAttributes().put("STIME", sTime);
                return chain.filter(exchange).then(Mono.fromRunnable(
                        () -> {
    
    
                            long stime = (long) exchange.getAttributes().get("STIME");
                            long cost = System.currentTimeMillis() - stime;
                            System.out.println("cost is : " + cost + " ms");
                        }));
            }
            @Override
            public String toString() {
    
    
                return filterToStringCreator(
                        CostGatewayFilterFactory.this)
                        .append(config.getSwitchStatus(), config.getSwitchStatus())
                        .toString();
            }
        };
    }
    public static class CustomConfig  {
    
    
        private String switchStatus;

        public String getSwitchStatus() {
    
    
            return switchStatus;
        }

        public void setSwitchStatus(String switchStatus) {
    
    
            this.switchStatus = switchStatus;
        }
    }
}

Configuration

routes:
  - id: gateway-provider
    uri: http://127.0.0.1:8088
    predicates:
      - Path=/provider/**
    filters:
      - StripPrefix=1
      - Cost=ON # 这个名字取前面GatewayFilterFactory的

Custom global

@Component
public class GlobalCustomFilter implements GlobalFilter {
    
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
        // 过滤前
        System.out.println("Before : " + exchange.getRequest().getURI());
        return chain.filter(exchange).then(Mono.fromRunnable(
                () -> {
    
    
                    long stime = (long) exchange.getAttributes().get("STIME");
                    long cost = System.currentTimeMillis() - stime;
                    System.out.println("End cost time is  : " +  cost);
                }));
    }
}

Spring Cloud Gateway is implemented based on Netty, not Tomcat. I originally wanted to try the priorities of mvc filters and gateway filters, but it didn't take effect no matter how I configured the filter. It turns out that a dishonest person is a dishonest person after all.
Can be replaced by Tomcat

Forward redirection principle

  • Gateway framework system processing entry org.springframework.http.server.reactive.ReactorHttpHandlerAdapter
  • Build the gateway context: org.springframework.web.server.adapter.HttpWebHandlerAdapter
  • Traverse the Mapping to obtain the Handler that actually handles the request org.springframework.web.reactive.DispatcherHandler
  • Build the filter chain: org.springframework.cloud.gateway.handler.FilteringWebHandler
  • The only path for filters: org.springframework.cloud.gateway.handler.FilteringWebHandler.DefaultGatewayFilterChain
  • Load balancing filter: org.springframework.cloud.gateway.filter.LoadBalancerClientFilter
  • Use Netty to send network request filter: org.springframework.cloud.gateway.filter.NettyRoutingFilter
    Insert image description here
    RouteToRequestUrlFilter This filter processes the Route configuration and stores the real address of the request in
URI mergedUrl = UriComponentsBuilder.fromUri(uri)
		// .uri(routeUri)
		.scheme(routeUri.getScheme()).host(routeUri.getHost())
		.port(routeUri.getPort()).build(encoded).toUri();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, mergedUrl);

NettyRoutingFilter makes the real forwarding call.
Insert image description here
This classic diagram must be pasted:
Insert image description here

Guess you like

Origin blog.csdn.net/qq_43259860/article/details/135365930