SpringCloud网关Zuul底层实现原理详解

2023年 7月 18日 54.7k 0

Zuul现在应用的已经非常少了,至少都在使用Spring Cloud Gateway。Zuul实现是基于Servlet这种阻塞是IO这种机制是通过创建更多的线程来弥补其不足;而Cloud Gateway则是基于反应式非阻塞式的,使用少量的线程来做更多的事。以下是官方对阻塞与非阻塞的对比图:

图片图片

1 收集路由

public class ZuulServerAutoConfiguration {
   @Autowired
   protected ZuulProperties zuulProperties;
   @Autowired
   protected ServerProperties server;
   // 主
   @Bean
   @Primary
   public CompositeRouteLocator primaryRouteLocator(
       Collection routeLocators) {
     return new CompositeRouteLocator(routeLocators);
   }
 
   @Bean
   @ConditionalOnMissingBean(SimpleRouteLocator.class)
   public SimpleRouteLocator simpleRouteLocator() {
     return new SimpleRouteLocator(this.server.getServlet().getContextPath(), this.zuulProperties);
   }
 }

SimpleRouteLocator

public class SimpleRouteLocator implements RouteLocator, Ordered {
   private ZuulProperties properties;
   private String dispatcherServletPath = "/";
   private String zuulServletPath;
   private AtomicReference routes = new AtomicReference();
   // servletPath = server.servlet.contextPath 配置属性值
   public SimpleRouteLocator(String servletPath, ZuulProperties properties) {
     this.properties = properties;
     if (StringUtils.hasText(servletPath)) {
       this.dispatcherServletPath = servletPath;
     }
     // 默认为:/zuul
     this.zuulServletPath = properties.getServletPath();
   }
 
   // 该方法会在CompositeRouteLocator中调用,而本例的作用就是将ZuulRoute转换为Route对象
   @Override
   public List getRoutes() {
     List values = new ArrayList();
     for (Entry entry : getRoutesMap().entrySet()) {
       ZuulRoute route = entry.getValue();
       String path = route.getPath();
       try {
         // 将配置文件中配置的ZuulRoute路由转换为Route对象
         values.add(getRoute(route, path));
       }
     }
     return values;
   }
   protected Map getRoutesMap() {
     if (this.routes.get() == null) {
       this.routes.set(locateRoutes());
     }
     return this.routes.get();
   }
   protected Map locateRoutes() {
     LinkedHashMap routesMap = new LinkedHashMap();
     // properties.getRouets获取配置文件中配置的所有路由
     for (ZuulRoute route : this.properties.getRoutes().values()) {
       routesMap.put(route.getPath(), route);
     }
     return routesMap;
   }
   protected Route getRoute(ZuulRoute route, String path) {
     String targetPath = path;
     // 获取配置文件的zuul.prefix属性值
     String prefix = this.properties.getPrefix();
     if (prefix.endsWith("/")) {
       // 删除 '/' 结尾的字符
       prefix = prefix.substring(0, prefix.length() - 1);
     }
     // 判断配置的路由path属性值的开始字符串是不是以 '/prefix/'开头,如:/api/
     // 如果配置的path:/api/api-1/**则匹配第一个条件,再判断zuul.strip-prefix属性值是否为true
     if (path.startsWith(prefix + "/") && this.properties.isStripPrefix()) {
       // 成立则会截取字符串删除'/prefix/'开头的字符,则最终targetPath = /api-1/**
       targetPath = path.substring(prefix.length());
     }
     // 如果配置为true
     if (route.isStripPrefix()) {
       // 知道path中第一个'*'
       int index = route.getPath().indexOf("*") - 1;
       // 如果存在
       if (index > 0) {
         // 截取第一个'*'之前的字符串
         // 如上:最终routePrefix = /api-1
         String routePrefix = route.getPath().substring(0, index);
         // 结合上面:targetPath = /**
         targetPath = targetPath.replaceFirst(routePrefix, "");
         // 结合上面:prefix = /api + /api-1 = /api/api-1
         prefix = prefix + routePrefix;
       }
     }
     // 上面的路径处理就是将配置的zuul.prefix + zuul.routes.xx.path
     Boolean retryable = this.properties.getRetryable();
     if (route.getRetryable() != null) {
       retryable = route.getRetryable();
     }
     // 构建Route对象
     return new Route(route.getId(), targetPath, route.getLocation(), prefix,
         retryable,
         route.isCustomSensitiveHeaders() ? route.getSensitiveHeaders() : null,
         route.isStripPrefix());
   }
 }

CompositeRouteLocator

public class CompositeRouteLocator implements RefreshableRouteLocator {
private final Collection

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论