zoukankan      html  css  js  c++  java
  • springboot+zuul(一)------实现自定义过滤器、动态路由、动态负载。

    参考:https://blog.csdn.net/u014091123/article/details/75433656 
    https://blog.csdn.net/u013815546/article/details/68944039

    Zuul是Netflix开源的微服务网关,他的核心是一系列的过滤器,通过这些过滤器我们可以轻松的实现服务的访问认证、限流、路由、负载、熔断等功能。

    基于对已有项目代码零侵入的需求,本文没有将zuul网关项目注册到eureka中心,而是将zuul与springboot结合作为一个独立的项目进行请求转发,因此本项目是非spring cloud架构。

    开始编写zuul网关项目 
    首先,新建一个spring boot项目。加入zuul依赖,开启@EnableZuulProxy注解。 
    pom.xml

    1 <dependency>
    2     <groupId>org.springframework.cloud</groupId>
    3     <artifactId>spring-cloud-starter-zuul</artifactId>
    4     <version>1.4.4.RELEASE</version>
    5 </dependency>

    application.properties

    1 server.port=8090
    2 eureka.client.enable=false
    3 zuul.ribbon.eager-load.enabled=true
    4 
    5 zuul.SendErrorFilter.post.disable=true

    由于后续会使用到动态路由,所以这里我们并不需要在application.properties中做网关地址转发映射。

    SpringBootZuulApplication.java

     1 package com.syher.zuul;
     2 
     3 import com.google.common.util.concurrent.ThreadFactoryBuilder;
     4 import com.syher.zuul.core.zuul.router.PropertiesRouter;
     5 import org.springframework.beans.factory.annotation.Autowired;
     6 import org.springframework.boot.CommandLineRunner;
     7 import org.springframework.boot.SpringApplication;
     8 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
     9 import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
    10 import org.springframework.cloud.netflix.zuul.RoutesRefreshedEvent;
    11 import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
    12 import org.springframework.context.ApplicationEventPublisher;
    13 import org.springframework.context.annotation.ComponentScan;
    14 
    15 import java.io.File;
    16 import java.util.concurrent.Executors;
    17 import java.util.concurrent.ScheduledExecutorService;
    18 import java.util.concurrent.TimeUnit;
    19 
    20 /**
    21  * @author braska
    22  * @date 2018/06/25.
    23  **/
    24 @EnableAutoConfiguration
    25 @EnableZuulProxy
    26 @ComponentScan(basePackages = {
    27         "com.syher.zuul.core",
    28         "com.syher.zuul.service"
    29 })
    30 public class SpringBootZuulApplication implements CommandLineRunner {
    31     @Autowired
    32     ApplicationEventPublisher publisher;
    33     @Autowired
    34     RouteLocator routeLocator;
    35 
    36     private ScheduledExecutorService executor;
    37     private Long lastModified = 0L;
    38     private boolean instance = true;
    39 
    40     public static void main(String[] args) {
    41         SpringApplication.run(SpringBootZuulApplication.class, args);
    42     }
    43 
    44     @Override
    45     public void run(String... args) throws Exception {
    46         executor = Executors.newSingleThreadScheduledExecutor(
    47                 new ThreadFactoryBuilder().setNameFormat("properties read.").build()
    48         );
    49         executor.scheduleWithFixedDelay(() -> publish(), 0, 1, TimeUnit.SECONDS);
    50     }
    51 
    52     private void publish() {
    53         if (isPropertiesModified()) {
    54             publisher.publishEvent(new RoutesRefreshedEvent(routeLocator));
    55         }
    56     }
    57 
    58     private boolean isPropertiesModified() {
    59         File file = new File(this.getClass().getClassLoader().getResource(PropertiesRouter.PROPERTIES_FILE).getPath());
    60         if (instance) {
    61             instance = false;
    62             return false;
    63         }
    64         if (file.lastModified() > lastModified) {
    65             lastModified = file.lastModified();
    66             return true;
    67         }
    68         return false;
    69     }
    70 }

    一、自定义过滤器

    自定义zuul过滤器比较简单。我们先讲过滤器。 
    zuul过滤器分为pre、route、post、error四种类型。作用我就不详细讲了,网上资料一大把。本文主要写路由前的过滤,即pre类型。 
    要自定义一个过滤器,只需要要继承ZuulFilter,然后指定过滤类型、过滤顺序、是否执行这个过滤器、过滤内容就OK了。

    为了便于扩展,这里用到了模板模式。 
    AbstractZuulFilter.java

     1 package com.syher.zuul.core.zuul.filter;
     2 
     3 import com.netflix.zuul.ZuulFilter;
     4 import com.netflix.zuul.context.RequestContext;
     5 import com.syher.zuul.core.zuul.ContantValue;
     6 
     7 /**
     8  * @author braska
     9  * @date 2018/06/29.
    10  **/
    11 public abstract class AbstractZuulFilter extends ZuulFilter {
    12 
    13     protected RequestContext context;
    14 
    15     @Override
    16     public boolean shouldFilter() {
    17         RequestContext ctx = RequestContext.getCurrentContext();
    18         return (boolean) (ctx.getOrDefault(ContantValue.NEXT_FILTER, true));
    19     }
    20 
    21     @Override
    22     public Object run() {
    23         context = RequestContext.getCurrentContext();
    24         return doRun();
    25     }
    26 
    27     public abstract Object doRun();
    28 
    29     public Object fail(Integer code, String message) {
    30         context.set(ContantValue.NEXT_FILTER, false);
    31         context.setSendZuulResponse(false);
    32         context.getResponse().setContentType("text/html;charset=UTF-8");
    33         context.setResponseStatusCode(code);
    34         context.setResponseBody(String.format("{"result":"%s!"}", message));
    35         return null;
    36     }
    37 
    38     public Object success() {
    39         context.set(ContantValue.NEXT_FILTER, true);
    40         return null;
    41     }
    42 }

    定义preFilter的抽象类,继承AbstractZuulFilter。指定pre类型,之后所有的pre过滤器都可以继承这个抽象类。 
    AbstractPreZuulFilter.java

     1 package com.syher.zuul.core.zuul.filter.pre;
     2 
     3 import com.syher.zuul.core.zuul.FilterType;
     4 import com.syher.zuul.core.zuul.filter.AbstractZuulFilter;
     5 
     6 /**
     7  * @author braska
     8  * @date 2018/06/29.
     9  **/
    10 public abstract class AbstractPreZuulFilter extends AbstractZuulFilter {
    11     @Override
    12     public String filterType() {
    13         return FilterType.pre.name();
    14     }
    15 }

    接着编写具体一个具体的过滤器,比如限流。 
    RateLimiterFilter.java

     1 package com.syher.zuul.core.zuul.filter.pre;
     2 
     3 import com.google.common.util.concurrent.RateLimiter;
     4 import com.syher.zuul.core.zuul.FilterOrder;
     5 import org.slf4j.Logger;
     6 import org.slf4j.LoggerFactory;
     7 
     8 import javax.servlet.http.HttpServletRequest;
     9 
    10 /**
    11  * @author braska
    12  * @date 2018/06/29.
    13  **/
    14 public class RateLimiterFilter extends AbstractPreZuulFilter {
    15 
    16     private static final Logger LOGGER = LoggerFactory.getLogger(RateLimiterFilter.class);
    17 
    18     /**
    19      * 每秒允许处理的量是50
    20      */
    21     RateLimiter rateLimiter = RateLimiter.create(50);
    22 
    23     @Override
    24     public int filterOrder() {
    25         return FilterOrder.RATE_LIMITER_ORDER;
    26     }
    27 
    28     @Override
    29     public Object doRun() {
    30         HttpServletRequest request = context.getRequest();
    31         String url = request.getRequestURI();
    32         if (rateLimiter.tryAcquire()) {
    33             return success();
    34         } else {
    35             LOGGER.info("rate limit:{}", url);
    36             return fail(401, String.format("rate limit:{}", url));
    37         }
    38     }
    39 }

    其他类型的过滤器也一样。创建不同的抽象类,比如AbstractPostZuulFilter,指定filterType,然后具体的postFilter只要继承该抽象类即可。

    最后,将过滤器托管给spring。 
    ZuulConfigure.java

     1 package com.syher.zuul.core.config;
     2 
     3 import com.netflix.loadbalancer.IRule;
     4 import com.netflix.zuul.ZuulFilter;
     5 import com.syher.zuul.core.ribbon.ServerLoadBalancerRule;
     6 import com.syher.zuul.core.zuul.filter.pre.RateLimiterFilter;
     7 import com.syher.zuul.core.zuul.filter.pre.TokenAccessFilter;
     8 import com.syher.zuul.core.zuul.filter.pre.UserRightFilter;
     9 import com.syher.zuul.core.zuul.router.PropertiesRouter;
    10 import org.springframework.beans.factory.annotation.Autowired;
    11 import org.springframework.boot.autoconfigure.web.ServerProperties;
    12 import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
    13 import org.springframework.context.annotation.Bean;
    14 import org.springframework.context.annotation.Configuration;
    15 
    16 /**
    17  * @author braska
    18  * @date 2018/07/05.
    19  **/
    20 @Configuration
    21 public class ZuulConfigure {
    22 
    23     @Autowired
    24     ZuulProperties zuulProperties;
    25     @Autowired
    26     ServerProperties server;
    27 
    28     /**
    29      * 动态路由
    30      * @return
    31      */
    32     @Bean
    33     public PropertiesRouter propertiesRouter() {
    34         return new PropertiesRouter(this.server.getServletPrefix(), this.zuulProperties);
    35     }
    36 
    37     /**
    38      * 动态负载
    39      * @return
    40      */
    41     @Bean
    42     public IRule loadBalance() {
    43         return new ServerLoadBalancerRule();
    44     }
    45 
    46     /**
    47      * 自定义过滤器
    48      * @return
    49      */
    50     @Bean
    51     public ZuulFilter rateLimiterFilter() {
    52         return new RateLimiterFilter();
    53     }
    54 }

    二、动态路由

    接着写动态路由。动态路由需要配置可持久化且能动态刷新。 
    zuul默认使用的路由是SimpleRouteLocator,不具备动态刷新的效果。DiscoveryClientRouteLocator具备刷新功能,但是需要已有的项目将服务注册到eureka,这不符合已有项目代码零侵入的需求所以排除。那么还有个办法就是自定义路由然后实现RefreshableRouteLocator类。

    部分代码如下: 
    AbstractDynamicRouter.java

     1 package com.syher.zuul.core.zuul.router;
     2 
     3 import com.syher.zuul.core.zuul.entity.BasicRoute;
     4 import org.apache.commons.lang.StringUtils;
     5 import org.slf4j.Logger;
     6 import org.slf4j.LoggerFactory;
     7 import org.springframework.beans.BeanUtils;
     8 import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
     9 import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
    10 import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
    11 
    12 import java.util.LinkedHashMap;
    13 import java.util.List;
    14 import java.util.Map;
    15 
    16 /**
    17  * @author braska
    18  * @date 2018/07/02.
    19  **/
    20 public abstract class AbstractDynamicRouter extends SimpleRouteLocator implements RefreshableRouteLocator {
    21 
    22     private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDynamicRouter.class);
    23 
    24     public AbstractDynamicRouter(String servletPath, ZuulProperties properties) {
    25         super(servletPath, properties);
    26     }
    27 
    28     @Override
    29     public void refresh() {
    30         doRefresh();
    31     }
    32 
    33     @Override
    34     protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {
    35         LinkedHashMap<String, ZuulProperties.ZuulRoute> routes = new LinkedHashMap<String, ZuulProperties.ZuulRoute>();
    36         routes.putAll(super.locateRoutes());
    37 
    38         List<BasicRoute> results = readRoutes();
    39 
    40         for (BasicRoute result : results) {
    41             if (StringUtils.isEmpty(result.getPath()) ) {
    42                 continue;
    43             }
    44             ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
    45             try {
    46                 BeanUtils.copyProperties(result, zuulRoute);
    47             } catch (Exception e) {
    48                 LOGGER.error("=============load zuul route info from db with error==============", e);
    49             }
    50             routes.put(zuulRoute.getPath(), zuulRoute);
    51         }
    52         return routes;
    53     }
    54 
    55     /**
    56      * 读取路由信息
    57      * @return
    58      */
    59     protected abstract List<BasicRoute> readRoutes();
    60 }

    由于本人比较懒。不想每次写个demo都要重新配置一大堆数据库信息。所以本文很多数据比如路由信息、比如负载策略。要么写在文本里面,要么直接java代码构造。 
    本demo的路由信息就是从properties里面读取。嗯,继承AbstractDynamicRouter即可。 
    PropertiesRouter.java

     1 package com.syher.zuul.core.zuul.router;
     2 
     3 import com.google.common.collect.Lists;
     4 import com.google.common.util.concurrent.ThreadFactoryBuilder;
     5 import com.syher.zuul.common.Context;
     6 import com.syher.zuul.core.zuul.entity.BasicRoute;
     7 import org.apache.commons.lang.StringUtils;
     8 import org.slf4j.Logger;
     9 import org.slf4j.LoggerFactory;
    10 import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
    11 
    12 import java.io.File;
    13 import java.io.IOException;
    14 import java.util.HashMap;
    15 import java.util.List;
    16 import java.util.Map;
    17 import java.util.Properties;
    18 import java.util.concurrent.Executors;
    19 import java.util.concurrent.ScheduledExecutorService;
    20 import java.util.stream.Collectors;
    21 
    22 /**
    23  * @author braska
    24  * @date 2018/07/02.
    25  **/
    26 public class PropertiesRouter extends AbstractDynamicRouter {
    27 
    28     private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesRouter.class);
    29     public static final String PROPERTIES_FILE = "router.properties";
    30     private static final String ZUUL_ROUTER_PREFIX = "zuul.routes";
    31 
    32 
    33     public PropertiesRouter(String servletPath, ZuulProperties properties) {
    34         super(servletPath, properties);
    35     }
    36 
    37     @Override
    38     protected List<BasicRoute> readRoutes() {
    39         List<BasicRoute> list = Lists.newArrayListWithExpectedSize(3);
    40         try {
    41             Properties prop = new Properties();
    42             prop.load(
    43                     this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE)
    44             );
    45 
    46             Context context = new Context(new HashMap<>((Map) prop));
    47             Map<String, String> data = context.getSubProperties(ZUUL_ROUTER_PREFIX);
    48             List<String> ids = data.keySet().stream().map(s -> s.substring(0, s.indexOf("."))).distinct().collect(Collectors.toList());
    49             ids.stream().forEach(id -> {
    50                 Map<String, String> router = context.getSubProperties(String.join(".", ZUUL_ROUTER_PREFIX, id));
    51 
    52                 String path = router.get("path");
    53                 path = path.startsWith("/") ? path : "/" + path;
    54 
    55                 String serviceId = router.getOrDefault("serviceId", null);
    56                 String url = router.getOrDefault("url", null);
    57 
    58                 BasicRoute basicRoute = new BasicRoute();
    59                 basicRoute.setId(id);
    60                 basicRoute.setPath(path);
    61                 basicRoute.setUrl(router.getOrDefault("url", null));
    62                 basicRoute.setServiceId((StringUtils.isBlank(url) && StringUtils.isBlank(serviceId)) ? id : serviceId);
    63                 basicRoute.setRetryable(Boolean.parseBoolean(router.getOrDefault("retry-able", "false")));
    64                 basicRoute.setStripPrefix(Boolean.parseBoolean(router.getOrDefault("strip-prefix", "false")));
    65                 list.add(basicRoute);
    66             });
    67         } catch (IOException e) {
    68             LOGGER.info("error to read " + PROPERTIES_FILE + " :{}", e);
    69         }
    70         return list;
    71     }
    72 }

    既然是动态路由实时刷新,那肯定需要一个定时器定时监控properties文件。所以我在启动类SpringBootZuulApplication加了个定时器监控properties是否发生过变更(之前有疑问的现在可以解惑了)。一旦文件被修改过就重新发布一下, 然后会触发routeLocator的refresh方法。

    1 public void publish() {
    2         if (isPropertiesModified()) {
    3             publisher.publishEvent(new RoutesRefreshedEvent(routeLocator));
    4         }
    5     }

    当然,如果是从数据库或者其他地方比如redis读取就不需要用到定时器,只要在增删改的时候直接publish就好了。

    最后,记得PropertiesRouter类交由spring托管(在ZuulConfigure类中配置bean)。

    router.properties文件:

    1 zuul.routes.dashboard.path=/**
    2 zuul.routes.dashboard.strip-prefix=true
    3 
    4 ##不使用动态负载需指定url
    5 ##zuul.routes.dashboard.url=http://localhost:9000/
    6 ##zuul服务部署后,动态增加网关映射,无需重启即可实时路由到新的网关
    7 ##zuul.routes.baidu.path=/**

    三、动态负载

    负载也算比较简单,复杂点的是写负载算法。 
    动态负载主要分两个步骤: 
    1、根据网关项目配置的host和port去数据库(我是java直接造的数据)查找负载策略,比如轮询、比如随机、比如iphash等等。 
    2、根据策略结合每台服务器分配的权重选出合适的服务。

    实现动态负载需要自定义rule类然后继承AbstractLoadBalancerRule类。 
    首先看负载策略的选择: 
    ServerLoadBalancerRule.java

     1 package com.syher.zuul.core.ribbon;
     2 
     3 import com.google.common.base.Preconditions;
     4 import com.netflix.client.config.IClientConfig;
     5 import com.netflix.loadbalancer.AbstractLoadBalancerRule;
     6 import com.netflix.loadbalancer.ILoadBalancer;
     7 import com.netflix.loadbalancer.Server;
     8 import com.syher.zuul.common.util.SystemUtil;
     9 import com.syher.zuul.core.ribbon.balancer.LoadBalancer;
    10 import com.syher.zuul.core.ribbon.balancer.RandomLoadBalancer;
    11 import com.syher.zuul.core.ribbon.balancer.RoundLoadBalancer;
    12 import com.syher.zuul.entity.GatewayAddress;
    13 import com.syher.zuul.service.GatewayService;
    14 import org.apache.commons.lang.StringUtils;
    15 import org.slf4j.Logger;
    16 import org.slf4j.LoggerFactory;
    17 import org.springframework.beans.factory.annotation.Autowired;
    18 import org.springframework.beans.factory.annotation.Value;
    19 
    20 /**
    21  * @author braska
    22  * @date 2018/07/05.
    23  **/
    24 public class ServerLoadBalancerRule extends AbstractLoadBalancerRule {
    25 
    26     private static final Logger LOGGER = LoggerFactory.getLogger(ServerLoadBalancerRule.class);
    27 
    28     @Value("${server.host:127.0.0.1}")
    29     private String host;
    30     @Value("${server.port:8080}")
    31     private Integer port;
    32 
    33     @Autowired
    34     private GatewayService gatewayService;
    35 
    36     @Override
    37     public void initWithNiwsConfig(IClientConfig iClientConfig) {
    38     }
    39 
    40     @Override
    41     public Server choose(Object key) {
    42         return getServer(getLoadBalancer(), key);
    43     }
    44 
    45     private Server getServer(ILoadBalancer loadBalancer, Object key) {
    46         if (StringUtils.isBlank(host)) {
    47             host = SystemUtil.ipList().get(0);
    48         }
    49         //Preconditions.checkArgument(host != null, "server.host must be specify.");
    50         //Preconditions.checkArgument(port != null, "server.port must be specify.");
    51 
    52         GatewayAddress address = gatewayService.getByHostAndPort(host, port);
    53         if (address == null) { //这里的逻辑可以改,找不到网关配置信息可以指定默认的负载策略
    54             LOGGER.error(String.format("must be config a gateway info for the server[%s:%s].", host, String.valueOf(port)));
    55             return null;
    56         }
    57 
    58         LoadBalancer balancer = LoadBalancerFactory.build(address.getFkStrategyId());
    59 
    60         return balancer.chooseServer(loadBalancer);
    61     }
    62 
    63     static class LoadBalancerFactory {
    64 
    65         public static LoadBalancer build(String strategy) {
    66             GatewayAddress.StrategyType type = GatewayAddress.StrategyType.of(strategy);
    67             switch (type) {
    68                 case ROUND:
    69                     return new RoundLoadBalancer();
    70                 case RANDOM:
    71                     return new RandomLoadBalancer();
    72                 default:
    73                     return null;
    74             }
    75         }
    76     }
    77 }

    然后是负载算法接口代码。 
    LoadBalancer.java

     1 package com.syher.zuul.core.ribbon.balancer;
     2 
     3 import com.netflix.loadbalancer.ILoadBalancer;
     4 import com.netflix.loadbalancer.Server;
     5 
     6 /**
     7  * @author braska
     8  * @date 2018/07/06.
     9  **/
    10 public interface LoadBalancer {
    11 
    12     /**
    13      * choose a loadBalancer
    14      * @param loadBalancer
    15      * @return
    16      */
    17     Server chooseServer(ILoadBalancer loadBalancer);
    18 }

    定义抽象类,实现LoadBalancer接口 
    AbstractLoadBalancer.java

     1 package com.syher.zuul.core.ribbon.balancer;
     2 
     3 import com.netflix.loadbalancer.ILoadBalancer;
     4 import com.netflix.loadbalancer.Server;
     5 import com.syher.zuul.core.SpringContext;
     6 import com.syher.zuul.service.ServerService;
     7 import org.slf4j.Logger;
     8 import org.slf4j.LoggerFactory;
     9 
    10 /**
    11  * @author braska
    12  * @date 2018/07/06.
    13  **/
    14 public abstract class AbstractLoadBalancer implements LoadBalancer {
    15     private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLoadBalancer.class);
    16     protected ServerService serverService;
    17 
    18     @Override
    19     public Server chooseServer(ILoadBalancer loadBalancer) {
    20         this.serverService = SpringContext.getBean(ServerService.class);
    21         Server server = choose(loadBalancer);
    22         if (server != null) {
    23             LOGGER.info(String.format("the server[%s:%s] has been select.", server.getHost(), server.getPort()));
    24         } else {
    25             LOGGER.error("could not find any server.");
    26         }
    27         return server;
    28     }
    29 
    30     public abstract Server choose(ILoadBalancer loadBalancer);
    31 }

    轮询负载算法 
    RoundLoadBalancer.java

     1 package com.syher.zuul.core.ribbon.balancer;
     2 
     3 import com.netflix.loadbalancer.ILoadBalancer;
     4 import com.netflix.loadbalancer.Server;
     5 import com.syher.zuul.common.Constant;
     6 import com.syher.zuul.core.GlobalCache;
     7 import com.syher.zuul.core.ribbon.LoadBalancerRuleUtil;
     8 import com.syher.zuul.entity.ServerAddress;
     9 
    10 import java.util.List;
    11 
    12 /**
    13  * 权重轮询
    14  * 首次使用取最大权重的服务器。而后通过权重的不断递减,寻找适合的服务器。
    15  * @author braska
    16  * @date 2018/07/06.
    17  **/
    18 public class RoundLoadBalancer extends AbstractLoadBalancer {
    19 
    20     private Integer currentServer;
    21     private Integer currentWeight;
    22     private Integer maxWeight;
    23     private Integer gcdWeight;
    24 
    25     @Override
    26     public Server choose(ILoadBalancer loadBalancer) {
    27         List<ServerAddress> addressList = serverService.getAvailableServer();
    28         if (addressList != null && !addressList.isEmpty()) {
    29             maxWeight = LoadBalancerRuleUtil.getMaxWeightForServers(addressList);
    30             gcdWeight = LoadBalancerRuleUtil.getGCDForServers(addressList);
    31             currentServer = Integer.parseInt(GlobalCache.instance().getOrDefault(Constant.CURRENT_SERVER_KEY, -1).toString());
    32             currentWeight = Integer.parseInt(GlobalCache.instance().getOrDefault(Constant.CURRENT_WEIGHT_KEY, 0).toString());
    33 
    34             Integer serverCount = addressList.size();
    35 
    36             if (1 == serverCount) {
    37                 return new Server(addressList.get(0).getHost(), addressList.get(0).getPort());
    38             } else {
    39                 while (true) {
    40                     currentServer = (currentServer + 1) % serverCount;
    41                     if (currentServer == 0) {
    42                         currentWeight = currentWeight - gcdWeight;
    43                         if (currentWeight <= 0) {
    44                             currentWeight = maxWeight;
    45                             if (currentWeight == 0) {
    46                                 GlobalCache.instance().put(Constant.CURRENT_SERVER_KEY, currentServer);
    47                                 GlobalCache.instance().put(Constant.CURRENT_WEIGHT_KEY, currentWeight);
    48                                 Thread.yield();
    49                                 return null;
    50                             }
    51                         }
    52                     }
    53 
    54                     ServerAddress address = addressList.get(currentServer);
    55                     if (address.getWeight() >= currentWeight) {
    56                         GlobalCache.instance().put(Constant.CURRENT_SERVER_KEY, currentServer);
    57                         GlobalCache.instance().put(Constant.CURRENT_WEIGHT_KEY, currentWeight);
    58                         return new Server(address.getHost(), address.getPort());
    59                     }
    60                 }
    61             }
    62 
    63         }
    64         return null;
    65     }
    66 }

    最后,ServerLoadBalancerRule交由spring托管。

    至此,springboot+zuul实现自定义过滤器、动态路由、动态负载就都完成了。 
    源码:https://github.com/rxiu/study-on-road/tree/master/trickle-gateway

  • 相关阅读:
    Windows环境下多版本JDK切换
    科学记数法数字转换/保留数值小数点位数(数字格式化)
    解析Excel数据
    odoo 配置文件参数大全
    odoo10 addon开发流程
    odoo10源码 windows环境安装
    【12】Django 中间件
    【10】Cookie和Session
    django-debug-toolbar
    爬虫系列之mongodb
  • 原文地址:https://www.cnblogs.com/braska/p/9645200.html
Copyright © 2011-2022 走看看