API网关服务:Spring Cloud Zuul

1.Zuul简介

1.1 zuul的位置

    zuul就像是整个微服务架构系统的门面,所有的外部客户端请求都需要经过它进行路由。
     

1.2 zuul执行流程



     简单来说zuul将请求转发,并提供pre,post,error类型过滤器,这些过滤器执行的时间不同,对应不同的阶段。

2.使用

2.1.添加依赖

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
 

2.2请求路由

传统路由方式
zuul.routes.api-server.path=/test/**
zuul.routes.api-server.url=http://localhost:8011/
面向服务的路由方式
zuul.routes.api-favorite.path=/Favorite/**
zuul.routes.api-favorite.serviceId=mem-favorite

本地跳转
zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.url=forward:/api/b

zull默认会将通过服务名(从服务中心拉取的信息)作为ContextPath的方式来创建路由映射。

2.3请求过滤

class PreFilter extends ZuulFilter {

    @Override
    String filterType() {
        return "pre"
    }

    @Override
    int filterOrder() {
        return -4
    }

    @Override
    boolean shouldFilter() {
        return true
    }

    @Override
    Object run() {
        HttpServletRequest context = RequestContext.getCurrentContext().getRequest()
        System.out.println("this is a pre filter")

        return null
    }
}

通过继承ZuulFilter抽象类并覆盖下面4个方法来实现自定义过滤器。
filterType:过滤器类型,它决定了过滤器执行的时机。
filterOrder:过滤器的属性。相同类型过滤器有多个的时候,通过这个决定执行的顺序。
shouldFilter:判断该过滤器是否需要执行。
run:过滤器的具体逻辑。

2.4自定义路由映射规则

public class PatternServiceRouteMapper implements ServiceRouteMapper {

   /**
    * A RegExp Pattern that extract needed information from a service ID. Ex :
    * "(?<name>.*)-(?<version>v.*$)"
    */
   private Pattern servicePattern;
   /**
    * A RegExp that refer to named groups define in servicePattern. Ex :
    * "${version}/${name}"
    */
   private String routePattern;

   public PatternServiceRouteMapper(String servicePattern, String routePattern) {
      this.servicePattern = Pattern.compile(servicePattern);
      this.routePattern = routePattern;
   }

只要创建PatternServiceRouteMapper Bean就可以了。参数是两个正则表达式。

2.5路径匹配

?  匹配任意单个字符
 *   匹配任意数量的字符
 **  匹配任意的字符,支持多级目录

3.zuul原理

3.1 ZuulServlet整体执行流程

@Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
    try {
        init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);

        // Marks this request as having passed through the "Zuul engine", as opposed to servlets
        // explicitly bound in web.xml, for which requests will not have the same data attached
        RequestContext context = RequestContext.getCurrentContext();
        context.setZuulEngineRan();

        try {
            preRoute();
        } catch (ZuulException e) {
            error(e);
            postRoute();
            return;
        }
        try {
            route();
        } catch (ZuulException e) {
            error(e);
            postRoute();
            return;
        }
        try {
            postRoute();
        } catch (ZuulException e) {
            error(e);
            return;
        }

    } catch (Throwable e) {
        error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
    } finally {
        RequestContext.getCurrentContext().unset();
    }
}

继续往下看,看到FilterProcessor类几个方法

public void postRoute() throws ZuulException {
    try {
        runFilters("post");
    } catch (ZuulException e) {
        throw e;
    } catch (Throwable e) {
        throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_POST_FILTER_" + e.getClass().getName());
    }
}
public void error() {
    try {
        runFilters("error");
    } catch (Throwable e) {
        logger.error(e.getMessage(), e);
    }
}
public void route() throws ZuulException {
    try {
        runFilters("route");
    } catch (ZuulException e) {
        throw e;
    } catch (Throwable e) {
        throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_ROUTE_FILTER_" + e.getClass().getName());
    }
}
public void preRoute() throws ZuulException {
    try {
        runFilters("pre");
    } catch (ZuulException e) {
        throw e;
    } catch (Throwable e) {
        throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName());
    }
}
继续看最终我们找到通过getFiltersByType获得相应的ZuulFilter

public List<ZuulFilter> getFiltersByType(String filterType) {

    List<ZuulFilter> list = hashFiltersByType.get(filterType);
    if (list != null) return list;

    list = new ArrayList<ZuulFilter>();

    Collection<ZuulFilter> filters = filterRegistry.getAllFilters();
    for (Iterator<ZuulFilter> iterator = filters.iterator(); iterator.hasNext(); ) {
        ZuulFilter filter = iterator.next();
        if (filter.filterType().equals(filterType)) {
            list.add(filter);
        }
    }
    Collections.sort(list); // sort by priority

    hashFiltersByType.putIfAbsent(filterType, list);
    return list;
}
我们看filterRegistry,查看谁调用了put方法我们找到了 ZuulFilterInitializer

@Override
public void contextInitialized(ServletContextEvent sce) {

   log.info("Starting filter initializer context listener");

   TracerFactory.initialize(tracerFactory);
   CounterFactory.initialize(counterFactory);

   for (Map.Entry<String, ZuulFilter> entry : this.filters.entrySet()) {
      filterRegistry.put(entry.getKey(), entry.getValue());
   }
}

我们看到是通过filters获得的,继续查看是谁实例化了ZuulFilterInitializer对象,我们找到了ZuulConfiguration类。代码如下

@Configuration
protected static class ZuulFilterConfiguration {

   @Autowired
   private Map<String, ZuulFilter> filters;

   @Bean
   public ZuulFilterInitializer zuulFilterInitializer(
         CounterFactory counterFactory, TracerFactory tracerFactory) {
      FilterLoader filterLoader = FilterLoader.getInstance();
      FilterRegistry filterRegistry = FilterRegistry.instance();
      return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry);
   }

}
最终我们看到了是通过自动注入获得了所有的ZuulFilter

 @Autowired
   private Map<String, ZuulFilter> filters;

3.2  Zuul默认提供的ZuulFilter




3.3动态路由

 和配置中心结合加入如下代码即可

@Bean
@RefreshScope
@ConfigurationProperties("zuul")
public ZuulProperties zullProperties() {
    return new ZuulProperties();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值