SpringCloud-源码分析 zuul (一)

本文作者:陈刚,叩丁狼高级讲师。原创文章,转载请注明出处。

zuul舍命周期

zuul,在SpringCloud中充当服务网关的角色,它包含了请求路由,过滤,安全等功能,可以说是我们web应用的“安保人员”,保证了我们“微服务园区”的安全,那么zuul是如何实现路由和过滤等功能的呢?我这里有一张摘抄于SpringCloud官网的zuul的生命周期图片

 

叩丁狼教育.png

叩丁狼教育.png

 

这张图的大致流程为:
1.当客户端请求过来首先会到 "pre" filters 这样的一个前置过滤器做一些处理,然后调用自定义的过滤器
2.前置过滤器执行完了之后会调用 “routing”filter 过滤器 ,看名字都知道这是做路由分发的过滤器
3.在路由的过程中出现了异常,那么会走 “error”filters过滤器,然后再走 "post"filters 过滤器 ,或者正常路由完成也会走到“post”filters
4."post"filters过滤器负责处理响应 ,最后把结果响应给客户端

这里是zuul大致的生命周期流程,我们看到它这里大量用到了filter进行处理,并且Zuul允许我们自定义Filter ,他提供了抽象的 ZuulFilter 过滤器,里面有四个基本方法,我们要自定义Filter就需要继承ZuulFilter,然后复写四个方法

/**
 服务过滤
 */
@Component
public class MyFilter extends ZuulFilter {


    /**
        返回过滤器的类型,过滤器类型如下:
        pre:请求路由之前调用过滤
        routing:请求routing之时调用过滤
        post: 请求路由之后调用过滤
        error:发送错误时调用过滤
     */
    @Override
    public String filterType() {
        return "pre";
    }

    //filterOrder:过滤的顺序
    @Override
    public int filterOrder() {
        return 0;
    }

    //shouldFilter:是否要过滤,true表示永远过滤。我们可以在这里做一写过滤处理
    @Override
    public boolean shouldFilter() {
        return true;
    }

 
  //当前过滤器的执行方法
  //我们可以在该方法中处理一些自己的判断
    @Override
    public Object run() {
        //获取请求对象
        RequestContext ctx = RequestContext.getCurrentContext();
        Object pass = ctx.getRequest().getParameter("pass");
        if(pass == null) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            try {
                ctx.getResponse().getWriter().write("pass is empty");
            }catch (Exception e){}
        }
        return null;
    }
}

那么我们接下来就分析他的源码就是去看这些内置的filter做了什么事情。

zuul的启动/配置

简单回顾一下zuul的使用 ,除了引入zuul相关依赖而外,我们要使用zull还需要在配置类上开启zuul功能

//@EnableZuulProxy :开启路由网关功能
@SpringBootApplication
@EnableZuulProxy
public class ServiceZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceZuulApplication.class, args);
    }
}

EnableZuulProxy的注释告诉我们,这里设设置Zuul服务器端点,和安装了一些过滤器,通过这些过滤器它可以转发请求到后端服务器

/**
 * Sets up a Zuul server endpoint and installs some reverse proxy filters in it, so it can
 * forward requests to backend servers. The backends can be registered manually through
 * configuration or via DiscoveryClient.
 *
 * @see EnableZuulServer for how to get a Zuul server without any proxying
 *
 * @author Spencer Gibb
 * @author Dave Syer
 * @author Biju Kunjummen
 */
@EnableCircuitBreaker
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyMarkerConfiguration.class)
public @interface EnableZuulProxy {
}

不过这里引入了 ZuulProxyMarkerConfiguration 配置类,这个配置在干嘛呢?

/**
 * Responsible for adding in a marker bean to trigger activation of 
 * {@link ZuulProxyAutoConfiguration}
 *
 * @author Biju Kunjummen
 */

@Configuration
public class ZuulProxyMarkerConfiguration {
    @Bean
    public Marker zuulProxyMarkerBean() {
        return new Marker();
    }

    class Marker {
    }
}

翻译:“Responsible for adding in a marker bean to trigger activation of

  • {@link ZuulProxyAutoConfiguration}”
    它在负责添加标记bean以触发激活 ZuulProxyAutoConfiguration 这个类,研究过springboot自动配置的同学就会知道 ,SpringBoot 中会有大量的 xxxAutoConfiguration 自动配置的类会在应用启动的过程中被激活实现自动装配,从而节省了我们很多的配置。

而这个类在配置些什么东西?

/**
 * @author Spencer Gibb
 * @author Dave Syer
 * @author Biju Kunjummen
 */
@Configuration
//这里引入了几种客户端配置
@Import({ RibbonCommandFactoryConfiguration.RestClientRibbonConfiguration.class,
        RibbonCommandFactoryConfiguration.OkHttpRibbonConfiguration.class,
        RibbonCommandFactoryConfiguration.HttpClientRibbonConfiguration.class,
        HttpClientConfiguration.class })
//如果存在了 ZuulProxyMarkerConfiguration.Marker的实例,该配置生效,这里是满足条件的
@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class)
public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration {
...省略代码...

ZuulProxyAutoConfiguration继承了 ZuulServerAutoConfiguration ,我们先看下这个配置类


/**
 * @author Spencer Gibb
 * @author Dave Syer
 * @author Biju Kunjummen
 */
@Configuration
@EnableConfigurationProperties({ ZuulProperties.class })
@ConditionalOnClass(ZuulServlet.class)
@ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class)
// Make sure to get the ServerProperties from the same place as a normal web app would
// FIXME @Import(ServerPropertiesAutoConfiguration.class)
public class ZuulServerAutoConfiguration {
  //绑定zuul的配置信息
    @Autowired
    protected ZuulProperties zuulProperties;

    @Autowired
    protected ServerProperties server;

//注入请求错误控制器
    @Autowired(required = false)
    private ErrorController errorController;

    @Bean
    public HasFeatures zuulFeature() {
        return HasFeatures.namedFeature("Zuul (Simple)", ZuulServerAutoConfiguration.class);
    }

//RouteLocator that composes multiple RouteLocators. :
//多路由组合定位器
    @Bean
    @Primary
    public CompositeRouteLocator primaryRouteLocator(
            Collection<RouteLocator> routeLocators) {
        return new CompositeRouteLocator(routeLocators);
    }

//简单的路由定位器
    @Bean
    @ConditionalOnMissingBean(SimpleRouteLocator.class)
    public SimpleRouteLocator simpleRouteLocator() {
        return new SimpleRouteLocator(this.server.getServlet().getServletPrefix(),
                this.zuulProperties);
    }


    @Bean
    public ZuulController zuulController() {
        return new ZuulController();
    }

// MVC HandlerMapping that maps incoming request paths to remote services.
//看名字也知道,他是做请求路径和远程服务的映射的,是  HandlerMapping的实现
    @Bean
    public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes) {
        ZuulHandlerMapping mapping = new ZuulHandlerMapping(routes, zuulController());
        mapping.setErrorController(this.errorController);
        return mapping;
    }

//定义ZuulRefreshListener  zuul刷新的监听器
    @Bean
    public ApplicationListener<ApplicationEvent> zuulRefreshRoutesListener() {
        return new ZuulRefreshListener();
    }

// Core Zuul servlet which intializes and orchestrates zuulFilter execution
//这里在注册ZuulServlet 这样的一个servlet, 这个东西了不得了,
//他是负责核心Zuul servlet初始化和调用zuulFilter执行,跟DispatcherServlet差不过
    @Bean
    @ConditionalOnMissingBean(name = "zuulServlet")
    public ServletRegistrationBean zuulServlet() {
        ServletRegistrationBean<ZuulServlet> servlet = new ServletRegistrationBean<>(new ZuulServlet(),
                this.zuulProperties.getServletPattern());
        // The whole point of exposing this servlet is to provide a route that doesn't
        // buffer requests.
        servlet.addInitParameter("buffer-requests", "false");
        return servlet;
    }

    // pre filters  : 
//前置过滤器,看名字是用来做检测的
    @Bean
    public ServletDetectionFilter servletDetectionFilter() {
        return new ServletDetectionFilter();
    }
//前置过滤器,是对请求数据做一些增强处理
    @Bean
    public FormBodyWrapperFilter formBodyWrapperFilter() {
        return new FormBodyWrapperFilter();
    }


    @Bean
    public DebugFilter debugFilter() {
        return new DebugFilter();
    }

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值