gateway官网文档解读(六) 汇总

终于整完了, 看了两天,中间还穿插各种面试和会议. 看了我的英语水平...或者说google的英译汉能力着实可以的.

看完之后有几个感受.

gateway本身分成三个组件

routes: 路由, 也是最小的颗粒组件

predicates: 断言, 就是满足什么样的条件

filter: 过滤器, 里面可以对请求做一些处理

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Cookie=mycookie,mycookievalue
        filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

这就是一个最简单的标准的一个路由里面有自己的

id(唯一标识),

predicates用来标记哪些请求进来,

filter代表着请求进来以后你要做什么,

这里面他提供了大批量的类库;

包括, 时间, cookie, url, 参数, header, 基本你能想到的东西都可以放到predicates和filter里面.他也比较希望你用它的类库.

从1~6 其实他就是在各种介绍他的类库.....不过我说实话.....太多了,整的我都不想用了,不是侥幸, 纯粹习惯问题.

Spring Cloud Gateway Diagram

这幅图要从上往下读: 请求进来, 进来以后经过两个handle,然后经过filter逐层的返回, 应该用的是责任链, 这个我还没有细看,后续去解读源码时候看看.

Example 59. ExampleConfiguration.java

@Bean
public GlobalFilter customFilter() {
    return new CustomGlobalFilter();
}

public class CustomGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

我喜欢这个:全局filter, 里面我们可以随意的写代码,各种搞事情,比如jwt. 

这时候有个问题了,如果多个filter他究竟是咋执行的

7.10. Marking An Exchange As Routed

网关路由ServerWebExchange之后,通过将gatewayAlreadyRouted添加到交换属性来将交换标记为“已路由”。 将请求标记为已路由后,其他路由筛选器将不会再次路由请求,实质上会跳过该过滤器。 您可以使用多种便捷方法将交换标记为已路由,或者检查交换是否已路由。

  • ServerWebExchangeUtils.isAlreadyRouted takes a ServerWebExchange object and checks if it has been “routed”.

  • ServerWebExchangeUtils.setAlreadyRouted takes a ServerWebExchange object and marks it as “routed”

也就是是说一个路由以后他就关闭了.其他的就不执行了,注意这里说的并不包括全局的,因为我创建了两个globalFilter都是执行的.那globalFilter呢,他的执行顺序是按照order执行的, 然后每个请求都必须执行.

我目前呢写了两个globalFilter, 一个是用来打印日志的, 另外一个是用来做jwt鉴权的.还有就是直接加一个@Component标签就行,不用非得声明一个@Bean,他的意思大概是希望你写的更加显式一点. 这个在

17. Developer Guide 导读更加明显.

我们看一下他的建议

17.1. Writing Custom Route Predicate Factories 编写自定义路由工厂

MyRoutePredicateFactory.java

public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {

    public MyRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        // grab configuration from Config object
        return exchange -> {
            //grab the request
            ServerHttpRequest request = exchange.getRequest();
            //take information from the request to see if it
            //matches configuration.
            return matches(config, request);
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

17.2. Writing Custom GatewayFilter Factories

To write a GatewayFilter, you must implement GatewayFilterFactory. You can extend an abstract class called AbstractGatewayFilterFactory. The following examples show how to do so:

Example 76. PreGatewayFilterFactory.java

public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {

    public PreGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            //If you want to build a "pre" filter you need to manipulate the
            //request before calling chain.filter
            ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
            //use builder to manipulate the request
            return chain.filter(exchange.mutate().request(builder.build()).build());
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

PostGatewayFilterFactory.java

public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {

    public PostGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                ServerHttpResponse response = exchange.getResponse();
                //Manipulate the response in some way
            }));
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

他把rotes,prediscates 和filter给分开了.而且可以prefilter和postFilter

下面我们结合我们立下的flag, 看看怎么搞重定向

现在我想把所有/action/*****的请求都变成/business

Example 8. application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment}

巴巴的说了好久了,停了好几天.因为在忙别的业务.在这里说一下最终解决方案

cloud:
  gateway:
    locator:
      enabled: true
    default-filters:
      - AddResponseHeader=X-Response-Default-Foo, Default-Bar
    # 服务自动发现,取第一个截取词匹配consul
    discovery:
      locator:
        lower-case-service-id: true
        enabled: true #开启根据微服务名称自动转发
        filters:
          - StripPrefix=1
    routes:
    - id: action
      uri: lb://business
      predicates:
      - Path= /action/**

没错,就是加了这么一个路由,这里加了一个断言predicates: 所有 /action/ 的请求 都被转发到注册中心的 business服务上.

比如http://gateway.com/action/abcServer 会被转译为 http://gateway.com/business/action/abcServer

-----------------------------------------------------

上边解决了路由转发,我们在这里在从头梳理一下我的需求

1.我有一个gateway, 一个consul 和一个business的主项目

2.我有一堆历史的债务有个叫做static的项目需要被整合到business里面,原因是里面就只有两个接口,一个2B同事搞得,个人感觉就是拿公司的服务玩.

3.我有个php的老项目api.com,原来有公网域名,现在需要整合进geteway,我需要把原有域名也可以正常通过gateway能访问到服务

4.我需要做一个负载均衡实现灰度

-------------------------------------

1.业务合并,上边已经解决了

2.现在我们做负载均衡和灰度

那么我们首先设置一个负载均衡的flag:假设我有两台服务, (ip分别是83,84),我这里是本地用端口91和92代替.91和92都已经注册到了consul(注册中心)上面.

  • 实现所有的请求20%在91上, 80%在92上
  • 实现header中所有请求studentId=123的学员请求都在92上
  • 实现header中所有请求按照studentId分群,将20%的比例固定的分配到91上,其他在92上
  • 实现header中url=abc的请求按照studentId分群,将20%的比例固定的分配到91上,其他在92上

回过来我们梳理一下无非就是按照url,studentId两个维度将流量分配给不同的服务. 好了现在我们需求有了,开始做个设计,

这个明显的是一个策略的模式,而且策略间应该是有优先级的.比如一个我们策略一是按照studentId%100<20在91,上策略2是studentId=123的在91上, 1,2明显是冲突的. 所以涉及到了优先级.

这个策略明显是不定长度的, 意思就是说比如url=abc的,后面还有url=bcd的,而且以后还可能有其他的项目.

最后初步设计这里采用责任链的方式,因为最后我们可以很明确的抽象出来几种规则有几个共性, 入参是studentId和url,回参是服务地址.

话不多说直接上代码:

-----------------------------兜兜转转,写完这个代码半个月了才想起来博客还没收尾--------------------------

首先yml的配置

#负载均衡
mybalance:
  open : true
  #灰度
  grayscale:
    - order: -129
      id: ver等于2.0.0的queryPort请求,投射到9091,ver不等于2.0.0的queryPort分发到其他服
      ip: 192.168.0.225:9091
      ver: '=2.0.0'
      url: '/statistics/testServer/queryPort'
      exclusive : 'trueUrl'
    - order: -128
      id: ver>=2.4.0的所有请求,投射到9091,ver小于2.4.0分发到其他服
      ip: 192.168.0.225:9092
      ver: '>2.4.0'
      url: '*'
      exclusive : 'trueVer'
    - order: -127
      id: studentId=123的,url=queryPort 投射到9091,其他请求随机投放
      ip: 192.168.0.225:9091
      studentId: 123
      url: '/statistics/testServer/queryPort2'
      exclusive : trueUrl
    - order: -125
      id: studentId=123的,url=queryPort 投射到9091,其他请求随机投放
      ip: 192.168.0.225:9091
      studentId: 123
      url: '*'
      exclusive : '*'

其次我们看看这个策略的解析类

@Api("灰度策略")
public class Grayscale {
    @ApiParam("优先级,值越小优先级越高,当出现了高优先级的负载均衡以后低优先级的就不再执行")
    private Integer order;
    @ApiParam("策略的唯一标识")
    private String id;
    @ApiParam("策略的ip标识,正则  consul中的address  ip或者ip+端口")
    private String ip;
    @ApiParam("header中studentId,正则,如果是*就代表所有")
    private String studentId;
    @ApiParam("请求的url,正则,如果是*就代表所有")
    private String url;
    @ApiParam("强制,true如果找不到对应ip就抛出异常,false:如果找不到对应的ip就随机返回一台 ")
    private boolean enforce=false;
    @ApiParam("权重0~100 当ip 有内容的时候本字段不生效")
    private Integer weight;
    @ApiParam("排他 如果之前的条件没有完全命中,那么就会执行exclusive过滤, 比如 trueStu 代表如果stu判断是true就会从服务列表摘除, falseStu代表如果stu是false就从列表摘除  ")
    private String exclusive;
    @ApiParam("版本号")
    private String ver;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getStudentId() {
        return studentId;
    }

    public void setStudentId(String studentId) {
        this.studentId = studentId;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public boolean isEnforce() {
        return enforce;
    }

    public void setEnforce(boolean enforce) {
        this.enforce = enforce;
    }

    public Integer getWeight() {
        return weight;
    }

    public void setWeight(Integer weight) {
        this.weight = weight;
    }

    public Integer getOrder() {
        return order;
    }

    public void setOrder(Integer order) {
        this.order = order;
    }

    public String getExclusive() {
        return exclusive;
    }

    public void setExclusive(String exclusive) {
        this.exclusive = exclusive;
    }

    public String getVer() {
        return ver;
    }

    public void setVer(String ver) {
        this.ver = ver;
    }

}

 

@Component
@ConditionalOnProperty( matchIfMissing = true ,prefix = "mybalance",name="open",havingValue = "true" )
@Api("负载均衡")
@ConfigurationProperties(prefix = "mybalance")
public class MyBalanceEntity {
    @ApiParam("灰度")
    private List<Grayscale> grayscale;

    @Constructor
    @ApiParam("所有策略")
    public void sort() {
        if (grayscale != null && grayscale.size() > 1) {
            grayscale.sort((g1, g2) -> {
                if (g2.getOrder() > g1.getOrder()) return 1;
                if (g2.getOrder() < g1.getOrder()) return -1;
                return 0;
            });
        }
    }

    public List<Grayscale> getGrayscale() {
        return grayscale;
    }

    public void setGrayscale(List<Grayscale> grayscale) {
        this.grayscale = grayscale;
    }
}

----------------------------------------这个可以看出来策略就是先按照id升序然后相同的按照前后顺序

/**
 * https://blog.csdn.net/zhou1124/article/details/103773835
 */
@Api("负载均衡,先执行MyLoadBalancerClientFilter,再执行MyLoadBalanceRule")
@Component
public class MyLoadBalancerClientFilter extends LoadBalancerClientFilter {
    public static ThreadLocal<ServerWebExchange> exchange = new ThreadLocal<>();
    private static Logger log = LoggerFactory.getLogger(DaishuCloudGatewayApplication.class);

    @Autowired
    private MyBalanceEntity myBalanceEntity;
    public MyLoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) {
        super(loadBalancer, properties);
    }

    @Override
    protected ServiceInstance choose(ServerWebExchange exchange) {
        //如果没有任何策略就使用
        if(myBalanceEntity==null||myBalanceEntity.getGrayscale()==null||myBalanceEntity.getGrayscale().size()==0){
            return super.choose(exchange);
        }
        //这里可以拿到web请求的上下文,可以从header中取出来自己定义的数据。
        MyLoadBalancerClientFilter.exchange.set(exchange);
        //获得真实的请求路径lb://statistics/testServer/queryPort
        URI uri = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
        HttpHeaders httpHeaders = exchange.getRequest().getHeaders();

        BalanceDto balanceDto=new BalanceDto(httpHeaders,uri);
        balanceDto.setHttpHeaders(httpHeaders);
        balanceDto.setUri(uri);

        log.info("步骤1");
        //如果在已有的ThreadLocal中没有连接
        if (MyLoadBalanceRule.originHost.get() == null) {
            //获得所属ip
            List<String> originHostHeader = httpHeaders.get(MyLoadBalanceRule.originHostHeader);
            if (originHostHeader == null || originHostHeader.size() == 0) {
                String host = exchange.getRequest().getURI().getHost();
                //设置请求头
                exchange.getRequest().mutate().header(MyLoadBalanceRule.originHostHeader, host).build();
                //设置本机地址
                MyLoadBalanceRule.originHost.set(host);
            } else {
                MyLoadBalanceRule.originHost.set(originHostHeader.get(0));
            }
        }
        //开始路由
        if (this.loadBalancer instanceof RibbonLoadBalancerClient) {
            RibbonLoadBalancerClient client = (RibbonLoadBalancerClient) this.loadBalancer;
            String serviceId = ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost();
            //这里使用userId做为选择服务实例的key, 调用的是MyLoadBalanceRule的choose, balanceDto 就是那边接收到的key
            return client.choose(serviceId, balanceDto);
        }
        return super.choose(exchange);
    }

}
@Component
@Api("路由规则")
public class MyLoadBalanceRule extends BestAvailableRule {
    private static Logger log = LoggerFactory.getLogger(DaishuCloudGatewayApplication.class);
    @Autowired
    @Qualifier("grayscaleBalance")
    private Balance grayscaleBalance;

    public static ThreadLocal<String> originHost=new ThreadLocal<>();
    public static  String originHostHeader="originHost";
    @Autowired
    private MyBalanceEntity myBalanceEntity;
    public Server choose(ILoadBalancer lb, Object key) {

        //log.info("步骤2"+key);
        if (lb == null) {
            log.error("MyLoadBalanceRule Exception no load balancer");
            return null;
        }
        if(myBalanceEntity==null||myBalanceEntity.getGrayscale()==null||myBalanceEntity.getGrayscale().size()==0){
            return  grayscaleBalance.loadRandomServer(lb.getReachableServers());
        }
        BalanceDto balanceDto=(BalanceDto) key;
        //consul 上的注册192.168.0.225:9091 192.168.0.225:9092 consul中服务对应的address项目
        List<Server> reachableServers = lb.getReachableServers();
        if(reachableServers==null ||reachableServers.size()==0){
            log.error("MyLoadBalanceRule Exception 没有可用的服务");
            return null;
        }
        balanceDto.setReachableServers(reachableServers);
        BalanceContext balanceContext=new BalanceContext(balanceDto);
        //进行负载均衡
        grayscaleBalance.chooseServer(balanceContext);
        //log.info("balanceContext:" + JSONObject.toJSONString(balanceContext));
        return  balanceContext.getServer();

    }
    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // TODO Auto-generated method stub

    }

}

//这两个类是负载均衡

先执行

MyLoadBalancerClientFilter

在执行

MyLoadBalanceRule
@Api("负载均衡的抽象规范,暂时没有其他用途")
public abstract class Balance {
    private static Logger log = LoggerFactory.getLogger(DaishuCloudGatewayApplication.class);
    @ApiParam("返回一台服务")
    public abstract void chooseServer(BalanceContext balanceContext);
    @ApiParam("随机返回一台服务")
    public abstract Server loadRandomServer(List<Server> serverList);


    @ApiParam("随机返回一台服务")
    protected void loadRandomServer(final @ApiParam("入参") BalanceContext balanceContext) {
        Server server= loadRandomServer(new ArrayList(balanceContext.getBalanceDto().getReachableServerMap().values()));
        balanceContext.setServer(server);
        balanceContext.setPolicyId("loadRandomServer");
    }

    @ApiParam("根据策略加载服务到context")
    protected void loadServer(final @ApiParam("灰度策略") Grayscale grayscale, final @ApiParam("入参") BalanceContext balanceContext) {
        if (Collections.isEmpty(balanceContext.getBalanceDto().getReachableServerMap())) {
            throw new DsException(10009);
        }
        MatchMap matchMap = new MatchMap();
        //判断是否命中
        effectiveStu(grayscale, balanceContext, matchMap);
        effectiveUrl(grayscale, balanceContext, matchMap);
        effectiveVer(grayscale, balanceContext, matchMap);
        //命中ip
        if (matchMap.isAllMatch()) {
            //构建context
            buildContextServer(grayscale, balanceContext);
        } else {
            //移除server
            exclusiveContextServer(grayscale, balanceContext, matchMap);
        }
    }

    @ApiParam("移除sever")
    private void exclusiveContextServer(Grayscale grayscale, BalanceContext balanceContext, @ApiParam("匹配结果") MatchMap matchMap) {
        //如果只剩下一台服务并且是一个有效的移除策略才开始移除
        if (balanceContext.getBalanceDto().getReachableServerMap().size() > 1 && DsStringUtil.isNotEmpty(grayscale.getExclusive()) && !grayscale.getExclusive().equals("*")) {
            String[] exp = grayscale.getExclusive().split(",");
            for (String str : exp) {
                switch (str) {
                    case "falseVer":
                        if (!matchMap.isVerMatch())
                            balanceContext.getBalanceDto().getReachableServerMap().remove(grayscale.getIp());
                        break;
                    case "trueVer":
                        if (matchMap.isVerMatch())
                            balanceContext.getBalanceDto().getReachableServerMap().remove(grayscale.getIp());
                        break;
                    case "trueUrl":
                        if (matchMap.isUrlMatch())
                            balanceContext.getBalanceDto().getReachableServerMap().remove(grayscale.getIp());
                        break;
                    case "falseUrl":
                        if (!matchMap.isUrlMatch())
                            balanceContext.getBalanceDto().getReachableServerMap().remove(grayscale.getIp());
                        break;
                    case "trueStu":
                        if (matchMap.isStuMatch())
                            balanceContext.getBalanceDto().getReachableServerMap().remove(grayscale.getIp());
                        break;
                    case "falseStu":
                        if (!matchMap.isStuMatch())
                            balanceContext.getBalanceDto().getReachableServerMap().remove(grayscale.getIp());
                        break;
                    default:
                }


            }
        }

    }

    @ApiParam("构建context")
    private void buildContextServer(Grayscale grayscale, BalanceContext balanceContext) {
        if (balanceContext.getBalanceDto().getReachableServerMap().get(grayscale.getIp()) != null) {
            balanceContext.setOrder(grayscale.getOrder());
            balanceContext.setPolicyId(grayscale.getId());
            balanceContext.setServer(balanceContext.getBalanceDto().getReachableServerMap().get(grayscale.getIp()));
        } else {
            if (grayscale.isEnforce()) {
                log.info("策略:" + grayscale.getId() + "没有找到服务==" + grayscale.getIp() + "强制执行失败");
                throw new DsException(10010, "策略id:" + grayscale.getId());
            } else {
                log.info("策略:" + grayscale.getId() + "没有找到服务==" + grayscale.getIp() + "跳过策略");
            }
        }
    }

    @ApiParam("匹配版本")
    private void effectiveVer(Grayscale grayscale, BalanceContext balanceContext, MatchMap matchMap) {
        //如果策略有但是header没有就不通过
        if (effective(grayscale.getVer()) && DsStringUtil.isEmpty(balanceContext.getBalanceDto().getHttpHeaders().getFirst("ver"))) {
            matchMap.setAllMatch(false);
            matchMap.setVerMatch(false);
            return;
        }
        if (effective(grayscale.getVer())) {
            DsHeader dsHeader = new DsHeader(balanceContext.getBalanceDto().getHttpHeaders());
            String ver = grayscale.getVer().replaceAll(">", "").replaceAll("=", "").replaceAll("<", "");
            //判断版本情况  header内容小于输入version版本返回-1    0 等于  header内容大于version返回1
            Integer i = dsHeader.afterVer(ver);
            //结果是小于
            if (i == -1 && !grayscale.getVer().startsWith("<")) {
                matchMap.setAllMatch(false);
                matchMap.setVerMatch(false);
            }
            //结果是大于
            if (i == 1 && !grayscale.getVer().startsWith(">")) {
                matchMap.setAllMatch(false);
                matchMap.setVerMatch(false);
            }
            //如果结果相等但是判断条件是不等于,或者不包含=
            if (i == 0 && (grayscale.getVer().startsWith("!=") || !grayscale.getVer().contains("="))) {
                matchMap.setAllMatch(false);
                matchMap.setVerMatch(false);
            }
        }
    }

    @ApiParam("判断地址匹配结果")
    private void effectiveUrl(Grayscale grayscale, BalanceContext balanceContext, MatchMap matchMap) {
        //如果需要检测url
        if (effective(grayscale.getUrl()) && !match(grayscale.getUrl(), balanceContext.getBalanceDto().getUri().toString())) {
            matchMap.setAllMatch(false);
            matchMap.setUrlMatch(false);
        }
    }

    @ApiParam("判断学生匹配结果")
    private void effectiveStu(Grayscale grayscale, BalanceContext balanceContext, MatchMap matchMap) {
        //如果策略有但是header没有
        if (effective(grayscale.getStudentId()) && DsStringUtil.isEmpty(balanceContext.getBalanceDto().getStudentId())) {
            matchMap.setAllMatch(false);
            matchMap.setStuMatch(false);
            return;
        }
        if (effective(grayscale.getStudentId()) && !match(grayscale.getStudentId(), balanceContext.getBalanceDto().getStudentId().toString())) {
            matchMap.setAllMatch(false);
            matchMap.setStuMatch(false);
        }
    }


    @ApiParam("是否是有效字段")
    private boolean effective(String str) {
        if (DsStringUtil.isEmpty(str) || str.trim().equals("*")) {
            return false;
        }
        return true;
    }

    @ApiParam("正则表达式是否匹配")
    private boolean match(@ApiParam("正则表达式") String exp, @ApiParam("内容") String str) {
        // 忽略大小写的写法
        Pattern pattern = Pattern.compile(exp, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str.replaceAll("lb://","/"));
        boolean rs = matcher.matches();
        return rs;
    }

}
@Api("灰度负载均衡")
@Component
public class GrayscaleBalance extends Balance {
    @Autowired
    private MyBalanceEntity myBalanceEntity;

    @Override
    public void chooseServer(BalanceContext balanceContext) {
        if (myBalanceEntity.getGrayscale() != null && myBalanceEntity.getGrayscale().size() > 0) {
            for (Grayscale grayscale : myBalanceEntity.getGrayscale()) {
                //如果还没有产生有效策略
                if (balanceContext.getServer() == null) {
                    //根据策略加载服务到context
                    super.loadServer(grayscale, balanceContext);
                } else {
                    //因为本身就已经进行过
                    break;
                }
            }
            //如果所有的都执行完了还没有拿到有效的策略
            if (balanceContext.getServer() == null) {
                super.loadRandomServer(balanceContext);
            }
        }
    }

    @ApiParam("随机返回一台服务")
    @Override
    public Server loadRandomServer(List<Server> serverList) {
        Random random = new Random();
        int index = random.nextInt(serverList.size());
        return serverList.get(index);
    }

}

//这两个类是实际的逻辑

这里面用了继承的方式倒不是说必须的,主要是考虑以后万一有扩展

通过这些配置就可以实现负载均衡的灰度, 其实如果需求不这么复杂的话还是建议用自带的断言和filter,或者自带的ribbon.可读性更好,性能也高.而且权重什么的也不用自己去做.主要还是看需求吧.

 

 

 

 

 

 

 

 

 

 

一、C语言自我YY 1)、C语言是许多高级计算机语言的基础,学好C语言能更好的学习其他高级语言,为以后的学习打基础;往深学C语言的话那就是学到C在Linux里的应用,Linux十分强大。 2)、C语言是一种计算机程序设计语言。具有高级语言的特点,又具有汇编语言的特点。C语言可作为工作系统设计语言,编写系统应用程序,也可以作为应用程序设计语言,编写不依赖计算机硬件的应用程序。 3)、应用范围广泛,具备很强的数据处理能力,不仅仅是在软件开发上,而且各类科研都需要用到C语言,适于编写系统软件,三维,二维图形和动画。具体应用比如单片机以及嵌入式系统开发。 4)、C语言是面向过程语言,C语言通过windows/linux平台下编译的,是直接运行在windows/linux平台下的,而XX始终是运行在他的虚拟机之上的;所以理论上C语言能做一些相对于比较底层的工作,像XX就不能编写Windows病毒。 5)、如果要利用编程来做一些windows优化工作的话,建议还是利用C语言。C语言是目前世界上流行、使用最广泛的高级程序设计语言 6、很多编译器,几乎所有操作系统Windows,Linux,Unix的大部分代码都是C,C在背后做了很多东西的,也许开发游戏用C++,安卓用XX更为合适,图形界面的用其他语言开发效率更高一些(因为他们封装了很多东西),但同样的原因导致略微接近底层的功能其他语言根本干不了!Windows的API都是按照C语言的格式给的,这也很能说明问题!嵌入式开发更是离不了C语言!纵观电脑发展几十年,C语无所不能呀!
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页