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