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

news2024/11/29 12:31:32

一、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在国内越来越少人用了,但是源码还是值得学习的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动力节点老杜Vue3视频笔记——Vue程序初体验

目录 一、Vue程序初体验 1.1 下载并安装vue.js 1.2 第一个Vue程序 1.3 Vue的data配置项 1.4 Vue的template配置项 一、Vue程序初体验 可以先不去了解Vue框架的发展历史、Vue框架有什么特点、Vue是谁开发的&#xff0c;对我们编写Vue程序起不到太大的作用&#xff0c;…

代码随想录_二叉树_leetcode654 617

leetcode654 最大二叉树 654. 最大二叉树 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀上 …

octave安装使用——吴恩达机器学习

下载octave 解压后双击octave.vbs进行安装 配置 pkg rebuildpkg list 使用基础命令 使用矩阵命令 移动数据 size&#xff1a;矩阵的行和列length&#xff1a;行和列的最大值 读取和存储数据 load&#xff1a;加载文件who&#xff1a;所有变量whos&#xff1a;更详细的变量…

界面开发框架Qt - 组合小部件映射器示例

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 Combo Widget Mappe…

人工智能实验二:约束满足问题

一、实验目的 求解约束满足问题&#xff1b;使用回溯搜索算法求解八皇后问题。 二、实验平台 课程实训平台https://www.educoder.net/paths/369 三、实验内容及步骤 实训内容&#xff1a;2-4 第六章 约束满足问题 1.问题描述 八皇后问题是指在一个 88 的棋盘上摆放八个皇…

Spark运行模式介绍

文章目录1. Local运行模式1.1 基本运行情况介绍1.2 角色划分1.3 Spark 任务提交与解释器对比2. StandAlone运行模式2.1 StandAlone介绍2.2 StandAlone架构2.3 Spark应用架构2.4 StandAlone HA 运行原理3. Spark on YARN3.1 Spark on Yarn 本质3.2 部署模式3.3 两种部署模式运行…

stata变量引用

stata变量引用–潘登同学的stata笔记 文章目录stata变量引用--潘登同学的stata笔记变量生成gen命令通配符&#xff1a;*, ?, -因子变量时间序列变量命名、前缀与标签变量命名、添加前缀通配符与批量重命名变量标签数字-文字对应表CSMAR数据处理查看、查找变量单值、暂元单值暂…

TCP网络连接的书写

TCP网络连接的书写 文章目录TCP网络连接的书写服务器端书写进程sock创建创建bind进行端口绑定(进行bind的初始化)监听socket获取链接用户端创建sock套接字connect进行连接服务器端书写 为TCP是面向连接,所有需要进行对于端口进行监控&#xff0c;另外的UDP的服务器就不需要进行…

洛克菲勒:世界上只有两种人头脑聪明...

洛克菲勒&#xff1a;被人称为“石油大王”、美国第一位十亿富豪与全球首富、创办芝加哥大学。洛克菲勒写给儿子的信共有38封&#xff0c;这些信真实记录了洛克菲勒创造财富神话的种种业绩。从这些信中我们不仅可以看到洛克菲勒优良的品德、卓越的经商才能&#xff0c;还可窥见…

Spring面向切面编程AOP使用介绍

文章目录AOPAOP核心概念AOP快速入门AOP工作流程AOP切入点表达式AOP通知类型AOP通知获取数据AOP总结AOP AOP核心概念 AOP(Aspect Oriented Programming)面向切面编程&#xff0c;一种编程范式&#xff0c;指导开发者如何组织程序结构 OOP(Object Oriented Programming)面向对象…

Web自动化测试的详细流程和步骤,一篇足矣

Web自动化测试是软件测试中非常重要的一种测试方法&#xff0c;它通过编写脚本来模拟人工操作网页&#xff0c;从而实现对Web应用程序进行自动化测试的过程。为了保证测试质量和效率&#xff0c;我们需要遵循一定的流程和步骤来完成Web自动化测试。 一、测试环境准备 在进行W…

webp怎么转换成png,4个方法教你快速处理

webp怎么转换成png&#xff1f;目前在一些比较大的图片素材网站下载的图片都是webp格式的。我们都知道webp格式图片&#xff0c;它在正常的图片浏览器中是无法打开的。 所以说我们要把webp图片转变成png格式&#xff0c;正常来说我们常用的图片处理软件也能进行格式转换&#x…

都说互联网不行了,真的是这样吗?

最近在马士兵教育的课堂上经常会听到学员说这样的话&#xff1a; 现在公司都不招人&#xff0c;程序员根本找不到工作 早知道IT行业这么难&#xff0c;当初就不学编程了 简历石沉大海、面试机会也没有&#xff0c;互联网是不是不行了 互联网行情到底如何&#xff1f; 作为…

从此告别写SQL!DataLeap帮你零门槛完成“数据探查”

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 在日常数据处理工作中&#xff0c;产品、运营、研发或数据分析师经常会面临数据量大且混乱、质量参差不齐的问题&#xff0c;需要花费大量时间和精力校验表数据是否…

车企外卷:一个关于智能手机的“围城故事”

从2016年达到顶峰开始&#xff0c;全球智能手机出货量逐年下行&#xff0c;手机市场进入红海竞争逐渐成为了各界的共识。此后全球疫情与经济疲软的影响也进一步在手机市场施压&#xff0c;很多媒体认为手机产业距离“至暗时刻”已经不远。而在去年&#xff0c;新增变数&#xf…

Velocity tools进阶(下篇)

最近自己所做的项目使用到这个Velocity模板引擎&#xff0c;分享一下在互联网找的学习资料&#xff0c;仅供学习使用&#xff0c;不参与任何商业活动。 一. VelocityTools介绍 1.1 VelocityTools简介 Velocity Tools 是 Velocity模板引擎的一个子项目&#xff0c;用于将 Velo…

Excel玩转自然语言查询

ChatGPT火出圈&#xff0c;人类被人工智能替代又成为热门话题。有人欢喜&#xff0c;有人忧&#xff0c;也有人不以为意&#xff0c;觉得离自己工作远着呢&#xff0c;比如现在是用Excel做报表&#xff0c;有本事你动动嘴就直接把Excel里面的数据查询出来啊。 你可别说&#xf…

metersphere逻辑整理

整体架构 Frontend: MeterSphere 的前端工程, 基于 Vue.js 进行开发。 Backend: MeterSphere 的后端工程, 基于 Spring Boot 进行开发, 为 MeterSphere 的功能主体。 Chrome Plugin: 浏览器插件, 录制 Web 访问请求生成 JMeter 脚本并导入到 MeterSphere 中用于接口测试及性能…

阿里云产品试用更新,产品组合试用装更划算,快来免费上云吧

最近阿里云产品又上新了&#xff0c;尤其是推出了最新的产品组合试用装&#xff0c;个人觉得阿里云关于云产品的更新迭代是非常重视的&#xff0c;而且每次推出的产品不仅会惊艳到用户&#xff0c;而且产品功能也是随着一次迭代而更加完善、强大。前段时间也写了一篇关于为什么…

Nginx服务配置及相关模块

目录一、Nginx简介1、Nginx简介2、I/O模型相关概念3、Nginx事件驱动模型4、Nginx和Apache的区别二、编译安装Nginx服务1.关闭防火墙&#xff0c;将安装的Nginx软件包安装到opt目录下2、编译安装Nginx3、创建用户、组&#xff0c;以便于更好的管理4、创建软连接并启动5、停止Ngi…