Spring Cloud微服务网关Zuul的注解@EnableZuulProxy或@EnableZuulServer做了什么事情

一、Zuul的工作原理

Zuul 1.x的版本是由Servlet以及一系列的Filter组成的,各个组件之间协同合作完成功能,且易于扩展。参看官方的架构图我画了张图:

Zuul声明周期:

HTTP Request -> DispatcherServlet -> ZuulHandlerMapping -> ZuulController -> ZuulServlet -> ZuulRunner -> FilterProcessor -> ZuulFilter -> HTTP Response

1、ZuulServlet通过RequestContext上下文管理着Zuul众多的Filter组成的核心组件。

2、当有请求进入Zuul时,由DispatcherServlet 进行分发交给ZuulHandlerMapping处理初始化得到路由定位器RouteLocator,为后续的请求分发做准备,同时也有基于事件从服务中心拉去服务列表(ZuulRefreshListener)。

3、ZuulController继承了ServletWrappingController重写了handleRequest方法将ZuulServlet引入声明周期,之后所有的请求都会经过ZuulServlet

4、在第一次调用的时候会初始化ZuulRunner,后面就会按照过滤链的顺序执行。ZuulRunner会将请求和相应初始化为RequestContext,封装成FilterProcessor转化为调用preRoute()route()postRoute()error()。所以在Zuul中获取请求都是通过RequestContext.getCurrentContext()先获取当前上下文,再通过上下文获取当前的请求。

二、@EnableZuulPoxy和@EnableZuulServer注解

@EnableCircuitBreaker
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyMarkerConfiguration.class)
public @interface EnableZuulProxy {
}



@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ZuulServerMarkerConfiguration.class)
public @interface EnableZuulServer {
}
复制代码

在网关的启动类上,添加注解@EnableZuulPoxy后就可以启动Zuul网关的功能。从上面的源码可以看到除了@EnableCircuitBreaker启动了熔断器外还引入了一个自动配置的类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 {
	}
}
复制代码

ZuulProxyMarkerConfiguration的源码十分简单啊!看不出什么来,不过注释里面说了添加Marker bean是为了触发ZuulProxyAutoConfiguration

@Configuration
@Import({ RibbonCommandFactoryConfiguration.RestClientRibbonConfiguration.class,
		RibbonCommandFactoryConfiguration.OkHttpRibbonConfiguration.class,
		RibbonCommandFactoryConfiguration.HttpClientRibbonConfiguration.class,
		HttpClientConfiguration.class })
@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class)
public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration {
	@Autowired(required = false)
	private List<RibbonRequestCustomizer> requestCustomizers = Collections.emptyList();
	@Autowired(required = false)
	private Registration registration;
	@Autowired
	private DiscoveryClient discovery;
	@Autowired
	private ServiceRouteMapper serviceRouteMapper;
	...
}
复制代码

很明显了@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class)条件注入。在ZuulProxyAutoConfiguration里面注入了很多的Bean

2.1 ZuulProxyAutoConfiguration

ZuulProxyAutoConfiguration继承了ZuulServerAutoConfiguration,拥有其全部功能并新增一下功能:

  • 引入HTTP客户端的配置:支持Apache HttpClient 和 OkHttp:通过@import注解引入配置,因为Zuul也是要发起HTTP请后网关后的服务,所以是需要HTTP客户端。
@Import({ RibbonCommandFactoryConfiguration.RestClientRibbonConfiguration.class,
		RibbonCommandFactoryConfiguration.OkHttpRibbonConfiguration.class,
		RibbonCommandFactoryConfiguration.HttpClientRibbonConfiguration.class,
		HttpClientConfiguration.class })
复制代码
  • 初始化服务注册、发现监听器:在发生服务注册到注册中心时触发路由刷新,DiscoveryClientRouteLocator完成路由新刷新功能。
@Bean
@ConditionalOnMissingBean(DiscoveryClientRouteLocator.class)
public DiscoveryClientRouteLocator discoveryRouteLocator() {
	return new DiscoveryClientRouteLocator(this.server.getServlet().getServletPrefix(), this.discovery, this.zuulProperties,
			this.serviceRouteMapper, this.registration);
}
复制代码
  • 初始化服务列表监听器

  • 初始化Zuul自定义Endpoint:

@Configuration
@ConditionalOnClass(Health.class)
protected static class EndpointConfiguration {
	@Autowired(required = false)
	private HttpTraceRepository traces;
	@Bean
	@ConditionalOnEnabledEndpoint
	public RoutesEndpoint routesEndpoint(RouteLocator routeLocator) {
		return new RoutesEndpoint(routeLocator);
	}
	@ConditionalOnEnabledEndpoint
	@Bean
	public FiltersEndpoint filtersEndpoint() {
		FilterRegistry filterRegistry = FilterRegistry.instance();
		return new FiltersEndpoint(filterRegistry);
	}
	@Bean
	public ProxyRequestHelper proxyRequestHelper(ZuulProperties zuulProperties) {
		TraceProxyRequestHelper helper = new TraceProxyRequestHelper();
		if (this.traces != null) {
			helper.setTraces(this.traces);
		}
		helper.setIgnoredHeaders(zuulProperties.getIgnoredHeaders());
		helper.setTraceRequestBody(zuulProperties.isTraceRequestBody());
		return helper;
	}
}
复制代码
  • 初始化一些内置的Filter(ZuulServerAutoConfiguration没有的Filter):根据HttpClient或OkHttp制定负载均衡的过滤器。
// pre filters
@Bean
@ConditionalOnMissingBean(PreDecorationFilter.class)
public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelpe
	return new PreDecorationFilter(routeLocator, this.server.getServlet().getServletPrefix(), this.zuulPropert
			proxyRequestHelper);
}
// route filters
@Bean
@ConditionalOnMissingBean(RibbonRoutingFilter.class)
public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper,
		RibbonCommandFactory<?> ribbonCommandFactory) {
	RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory,
			this.requestCustomizers);
	return filter;
}
@Bean
@ConditionalOnMissingBean({SimpleHostRoutingFilter.class, CloseableHttpClient.class})
public SimpleHostRoutingFilter simpleHostRoutingFilter(ProxyRequestHelper helper,
		ZuulProperties zuulProperties,
		ApacheHttpClientConnectionManagerFactory connectionManagerFactory,
		ApacheHttpClientFactory httpClientFactory) {
	return new SimpleHostRoutingFilter(helper, zuulProperties,
			connectionManagerFactory, httpClientFactory);
}
@Bean
@ConditionalOnMissingBean({SimpleHostRoutingFilter.class})
public SimpleHostRoutingFilter simpleHostRoutingFilter2(ProxyRequestHelper helper,
													   ZuulProperties zuulProperties,
													   CloseableHttpClient httpClient) {
	return new SimpleHostRoutingFilter(helper, zuulProperties,
			httpClient);
}
复制代码

2.2 ZuulServerAutoConfiguration

同时可以看到ZuulProxyAutoConfiguration是继承了ZuulServerAutoConfiguration。同样@ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class)条件注入。所以说@EnableZuulProxy会把ZuulServerAutoConfigurationZuulServerAutoConfiguration注入到Spring容器中。

很大一部分的组件实在ZuulServerAutoConfiguration中注入到Spring容器的:

@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 {
	...
}
复制代码
  • 初始化配置加载器:读取配置文件中的配置
@Autowired
protected ZuulProperties zuulProperties;
复制代码
  • 初始化路由加载器:这里的路由加载器都是加载本地配置文件中配置的路由信息。如果是想要自己实现路由加载器,例如像DiscoveryClientRouteLocator就是注册中心发生注册事件时,加载新的服务路由的加载器。如果是基于数据库存储做动态路由信息,也要自己实现一个路由加载器。
@Bean
@Primary
public CompositeRouteLocator primaryRouteLocator(
		Collection<RouteLocator> routeLocators) {
    // 这里整合所有的路由加载器,像要刷新路由时,会遍历Spring容器内所有的路由加载器一个个去刷新。
	return new CompositeRouteLocator(routeLocators);
}
@Bean
@ConditionalOnMissingBean(SimpleRouteLocator.class)
public SimpleRouteLocator simpleRouteLocator() {
    // 这是最基本的路由加载器,无论是DiscoveryClientRouteLocator还是自定义的都需要继承SimpleRouteLocator
    // 所有的路由信息最终都会加载出来,被SimpleRouteLocator管理着
	return new SimpleRouteLocator(this.server.getServlet().getServletPrefix(),
			this.zuulProperties);
}
复制代码
  • 初始化路由映射器:它会根据请求路径,通过路由加载器匹配可以访问的服务
@Bean
public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes) {
	ZuulHandlerMapping mapping = new ZuulHandlerMapping(routes, zuulController());
	mapping.setErrorController(this.errorController);
	return mapping;
}
复制代码
  • 初始化路由刷新监听器:这个是很核心的配置,因为这里监听着各种会触发路由刷新的事件。
@Bean
public ApplicationListener<ApplicationEvent> zuulRefreshRoutesListener() {
	return new ZuulRefreshListener();
}

private static class ZuulRefreshListener
		implements ApplicationListener<ApplicationEvent> {
	@Autowired
	private ZuulHandlerMapping zuulHandlerMapping;
	private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor();
	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ContextRefreshedEvent
				|| event instanceof RefreshScopeRefreshedEvent
				|| event instanceof RoutesRefreshedEvent
				|| event instanceof InstanceRegisteredEvent) {
			reset();
		}
		else if (event instanceof ParentHeartbeatEvent) {
			ParentHeartbeatEvent e = (ParentHeartbeatEvent) event;
			resetIfNeeded(e.getValue());
		}
		else if (event instanceof HeartbeatEvent) {
			HeartbeatEvent e = (HeartbeatEvent) event;
			resetIfNeeded(e.getValue());
		}
	}
	private void resetIfNeeded(Object value) {
		if (this.heartbeatMonitor.update(value)) {
			reset();
		}
	}
	private void reset() {
		this.zuulHandlerMapping.setDirty(true);
	}
}
复制代码
  • 初始化ZuulServlet加载器
@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;
}
复制代码
  • 初始化ZuulController
@Bean
public ZuulController zuulController() {
	return new ZuulController();
}
复制代码
  • 初始化Filter执行解析器
@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);
	}
}@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);
	}
}
复制代码
  • 初始化一些内置的Filter:基本的过滤器,也是经常会在很多Zuul过滤链组成图中经常看到。
@Bean
public ServletDetectionFilter servletDetectionFilter() {
	return new ServletDetectionFilter();
}
@Bean
public FormBodyWrapperFilter formBodyWrapperFilter() {
	return new FormBodyWrapperFilter();
}
@Bean
public DebugFilter debugFilter() {
	return new DebugFilter();
}
@Bean
public Servlet30WrapperFilter servlet30WrapperFilter() {
	return new Servlet30WrapperFilter();
}
// post filters
@Bean
public SendResponseFilter sendResponseFilter(ZuulProperties properties) {
	return new SendResponseFilter(zuulProperties);
}
@Bean
public SendErrorFilter sendErrorFilter() {
	return new SendErrorFilter();
}
@Bean
public SendForwardFilter sendForwardFilter() {
	return new SendForwardFilter();
}
复制代码
  • 初始化Metrix监控
@Configuration
protected static class ZuulMetricsConfiguration {
	@Bean
	@ConditionalOnMissingBean(CounterFactory.class)
	public CounterFactory counterFactory() {
		return new EmptyCounterFactory();
	}
	@ConditionalOnMissingBean(TracerFactory.class)
	@Bean
	public TracerFactory tracerFactory() {
		return new EmptyTracerFactory();
	}
}
复制代码

三、总结

本文配了较多的源码,主要是ZuulProxyAutoConfigurationZuulServerAutoConfiguration这两个SpringBoot自动配置类,涵盖了很多Zuul的组件,花点时间去阅读、debug会让你很快去了解去很多的工作流程和原理。虽然Zuul在国内越来越少人用了,但是源码还是值得学习的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/12789.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面了 6 家大厂,并拿下 5 家 offer,进大厂好像也没有那么困难吧....

前言 二月份的时候因为换工作的缘故&#xff0c;陆续参加了华为、阿里巴巴、字节跳动、拼多多、百度、Paypal 的社招面试&#xff0c;除了字节跳动流程较长&#xff0c;我主动结束面试以外&#xff0c;其他的都顺利拿到了 Offer。 最近时间稍微宽裕点了&#xff0c;写个面经&…

2021遥感应用组二等奖:近20年黄河流域植被动态与生态环境效应

作品介绍 1 研究目的 基于MODIS NDVI植被指数、土地利用数据和气象数据集&#xff0c;辅以趋势分析、偏相关分析、马尔科夫转移矩阵变化分析、多元回归分析等方法&#xff0c;全面分析黄河流域2001-2020年植被时空变化特征&#xff0c;并通过构建统计模型方式&#xff0c;定量…

图染色问题的NP完全性证明

文章目录 1.Overview2.CNF 3-sat3. Gadgets3.1 Concolorous Edges3.2 Starter/Variable Gadget3.3 Splitter Gadget3.4 OR Gadget3.5 Clause Gadget 4. To Planar Graph 最近在学 6.890&#xff0c;然后 devans 刚好问了我这个问题&#xff0c;然后尝试编了一个证明。 1.Overv…

独家 | 招商银行:玩转校园招聘新方式 挖掘金融科技新人才

数字经济时代&#xff0c;金融科技人才队伍的引进与培养是招商银行人才体系建设的关键任务。 01.金融科技校招2大核心课题 招商银行数字化转型过程中&#xff0c;线上化、生态化、平台化、智能化、数据化全面加速发展&#xff0c;对人才队伍能力提出新要求。 2大核心课题&am…

Spring Bean的生命周期

Spring Bean 的完整生命周期主要包括以下阶段&#xff1a; 实例化&#xff08;Instantiation&#xff09;&#xff1a;Spring 容器通过调用 Bean 的构造函数来创建 Bean 的实例。这是 Bean 生命周期的第一步。 设置属性值&#xff08;Setting Bean Properties&#xff09;&…

【分布式】熔断、降级傻傻分不清楚-熔断和降级的真实关系

文章目录 前言降级熔断什么是服务熔断 熔断和降级的关系降级方式1、熔断降级&#xff08;不可用&#xff09;2、超时降级3、限流降级 总结 前言 刚开始我以为熔断和降级是一体的&#xff0c;以为他们必须配合使用&#xff1b; 只不过名字不一样而已&#xff0c;但是当我经过思…

如何实现视觉识别形状

1. 功能说明 通过摄像头识别圆形及矩形两种形状。 2. 电子硬件 本实验中采用了以下硬件&#xff1a; 主控板 Basra主控板&#xff08;兼容Arduino Uno&#xff09; 扩展板 Bigfish2.1 电池7.4V锂电池通信2510通信转接板WiFi路由器 其它 摄像头 配置OpenCV的Visual Studio 2015.…

MySQL having关键字详解、与where的区别

1、having关键字概览 1.1、作用 对查询的数据进行筛选 1.2、having关键字产生的原因 使用where对查询的数据进行筛选时&#xff0c;where子句中无法使用聚合函数&#xff0c;所以引出having关键字 1.3、having使用语法 having单独使用&#xff08;不与group by一起使用&a…

(SQL学习随笔3)SQL语法——SELECT语句

导航 基本认识FROM关键字LIMIT与OFFSETORDER BY WHERE条件查询单值比较多条件组合范围筛选空值匹配LIKE通配条件分组 运算符和函数数据变换 分组运算表连接内连接左(右)外连接全外连接 外键约束窗口函数UNION&#xff1a;表上下拼接子查询条件判断PostgreSQLMySQL 基本认识 SE…

两种方法实现杨辉三角(java实现)

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…

Consul TTL健康检查方式

consul比较常用的健康检查方式为http健康检查方式&#xff0c;也还有使用TTL方式来进行健康检查的&#xff0c;下面从spring-cloud-consul-discovery这个SDK来着手分析。 构建ConsulAutoRegistration&#xff0c;这里的工作是组成服务注册的报文&#xff0c;有一个setCheck方法…

钉钉消息防撤回功能研究与实现-可查看历史消息[文件/图文/管理员/链接 撤回拦截]

研究背景 由于在某个大学进行上课的时候,遇到的某个老师,总是习惯发过的消息,到第二天的时候撤回,我们用聊天工具的其中一个原因,不就是因为可以随时去查看发过的消息吗&#xff0c;&#xff0c;而这位老师的操作,也让包括我在内的很多人感到痛不欲生。 想一想,当自己想要去看下…

常见的九种大数据分析模型

常见的9种大数据分析模型分别为&#xff1a; 事件分析、 属性分析、 渠道分析、 Session分析、 留存分析、 归因分析、 漏斗分析、 路径分析、 分布分析 1、【事件分析】 事件分析&#xff0c;是指用户在 APP、网站等应用上发生的行为&#xff0c;即何人&#xff0c;何时&…

【消费战略】解读100个食品品牌丨王小卤 4年10亿爆品破局

爆品破局 王小卤的聚焦发展! 王小卤创建于 2016 年&#xff0c;与饮料行业的独角兽元气森林同年。 相较于元气森林的快速增长&#xff0c;王小卤历经 三年坎坷之路&#xff0c;直至 2019 年才踏上高增长的赛道&#xff0c;实现四年十亿的增长。 “所有的消费品都值得重新 做…

网络安全-kali配置ssh服务+敏感文件泄+dirsearch脚本

网络安全-kali配置ssh服务敏感文件泄dirsearch脚本 seccure shell 就是加密的telnet 远程用的 service ssh start 开启ssh服务metstat -tpan |gerp 22 监听这个端口是否开启 可以看到本地的22端口这个文件是/etc/ssh/sshd_config 输入 set number 找到第57行 把这个前面的#注…

【记录】Truenas Scale|中危漏洞,需要SMB签名

部分内容参考&#xff1a;等保测试问题——需要SMB签名(SMB Signing not Required) 以及 ChatGPT。 Truenas常用SMB服务&#xff0c;但默认并不开启SMB签名。这样具有中间人攻击的风险。 一、漏洞详情 1.1 漏洞报告 漏洞提示如下&#xff1a; 1.2 漏洞介绍 SMB是一个协议名…

人工智能发展到GPT4经历了什么,从专家系统到机器学习再到深度学习,从大模型到现在的GPT4

大家好&#xff0c;我是微学AI&#xff0c;今天给大家讲一下人工智能的发展&#xff0c;从专家系统到机器学习再到深度学习&#xff0c;从大模型到现在的GPT4&#xff0c;讲这个的目的是让每个人都懂得人工智能&#xff0c;每个人都懂得人工智能的发展&#xff0c;未来人工智能…

4.13(LoadLibrary)

接着之前预习的知识&#xff0c;我观察的自己编译出来的bin LoadLibraryExA LoadLibraryExA函数进去&#xff0c;现时用RtInitAnsiString函数初始化了ANSI的计数字符串&#xff0c;底层是调用了LoadLibraryExW函数&#xff0c;在LoadLibrarExW函数里做了unicode的计数字符串的…

python入门(五) vscode配置Anaconda 环境,代码自动提示

文章目录 1.conda的下载地址:1.配置conda的环境变量安装conda配置path 2.vcode配置python插件3.配置conda1) Select Interpreter2) 选择conda环境 4.测试 vscode配置Anaconda 环境&#xff0c;代码自动提示. 本人工作中&#xff0c;用到了ai相关技术&#xff0c;但是java出身&a…

七项新发布,亚马逊云科技Amazon S3持续进化

17年前的3月14日&#xff0c;亚马逊云科技推出了一项“非常简单的”对象存储服务&#xff08;Amazon Simple Storage Service&#xff09;。该服务允许开发人员创建、列出和删除私有存储空间&#xff08;称为存储桶&#xff09;、上传和下载文件以及管理其访问权限。当时&#…