欢迎来到【成品W灬源码1688】【物流网站含app源码】【我买的燕窝没有溯源码】监听器源码_监听代码是多少-皮皮网网站!!!

皮皮网

【成品W灬源码1688】【物流网站含app源码】【我买的燕窝没有溯源码】监听器源码_监听代码是多少-皮皮网 扫描左侧二维码访问本站手机端

【成品W灬源码1688】【物流网站含app源码】【我买的燕窝没有溯源码】监听器源码_监听代码是多少

2024-12-24 09:51:42 来源:{typename type="name"/} 分类:{typename type="name"/}

1.Vert.x 源码解析(4.x)——Future源码解析
2.一文详解RocketMQ-Spring的监听源码解析与实战
3.物联网设备常见的web服务器——uhttpd源码分析(二)
4.关于java的监听器
5.如何在ASP.NET Core 6中使用跟踪监听器
6.图解+源码讲解 Nacos 客户端动态监听配置机制

监听器源码_监听代码是多少

Vert.x 源码解析(4.x)——Future源码解析

       在现代软件开发中,异步编程的器源重要性日益凸显,提升并发性能并处理大量并行操作。码监码多Vert.x,听代作为一款基于事件驱动和非阻塞设计的监听异步框架,提供了丰富的器源成品W灬源码1688工具简化异步编程。本文将深入解析Vert.x 4.x版本的码监码多Future源码,理解其关键类和功能。听代

       1. 异步核心

       Vert.x的监听核心在于FutureImpl和PromiseImpl,它们是器源实现异步操作的关键。AsyncResult是码监码多通用接口,用于表示异步操作的听代结果,包含成功值或失败异常。监听

       2. Future类详解

       Future扩展了AsyncResult,器源提供了组合操作如join、码监码多any、all和map等功能。内部的FutureInternal主要负责添加监听器,FutureBase负责执行监听器和转换函数。

       具体来说,FutureImpl的onComplete方法接收一个handler,任务完成后执行,物流网站含app源码而tryComplete则在异步操作有结果时触发,最终调用用户指定的handler。

       相比之下,Promise允许用户手动设置异步结果,PromiseImpl继承自FutureImpl,并增加了context获取功能。

       3. 实例与源码分析

       通过简单的入门实例,如独立使用Future,我们可以看到Vert.x如何通过创建PromiseImpl获取Future。源码分析显示,Promise.future获取Future,OnComplete用于添加监听,而complete方法则用于设置值并通知监听器。

       4. 深入源码

       在源码层面,addListener和emitSuccess方法在OnComplete中扮演重要角色。而complete方法,特别是tryComplete,是设置值并触发监听的关键。

       5. 总结

       总的来说,理解Vert.x中的Future,就是我买的燕窝没有溯源码创建PromiseImpl获取Future,通过OnComplete添加监听器,然后通过Promise的complete方法设置值并通知监听器。后续还将深入探讨其他Future实现类,如all、any和map的原理。

一文详解RocketMQ-Spring的源码解析与实战

       RocketMQ-Spring源码解析与实战概览

       这篇文章详细阐述了在Spring Boot项目中如何运用rocketmq-spring SDK进行消息收发,以及开发者视角下SDK的设计逻辑。通过一步步操作流程,理解其在生产者和消费者端的实际应用。

       SDK简介

       rocketmq-spring本质上是一个Spring Boot启动器,通过“约定优于配置”的理念简化集成过程。只需在pom.xml中引入依赖,并在配置文件中进行简单的配置,如添加名字服务地址和生产者组。

       配置与操作流程

       1. 在pom.xml引入依赖并配置,如生产者和消费者配置。

       生产者配置:包含名字服务地址和生产者组

       消费者配置:实现消息监听器

       核心源码分析

       rocketmq-spring的核心模块包括启动器、SDK模块和示例代码模块,源码中着重解析了RocketMQTemplate类和消费者启动机制,如生产者模板封装和消费者消息处理逻辑。

       生产者模板与消费者启动

       生产者:通过RocketMQProperties对象绑定配置,来玩葫芦鱼房卡源码创建生产者Bean并整合到RocketMQTemplate中

       消费者:通过ListenerContainerConfiguration自动启动,封装RocketMQListener的消费逻辑

       进阶学习

       要深入学习rocketmq-spring,可以从实际操作、模块设计、starter设计思路和源码理解四个方面逐步提升。

物联网设备常见的web服务器——utl` 函数通过改变已打开文件的性质来实现对文件的控制,具体操作包括改变描述符的属性,为后续的服务器操作提供灵活性。关于这一函数的使用,详细内容可参考相关技术文档。

       `uh_setup_listeners` 函数在服务器配置中占有重要地位,主要关注点在于设置监听器的回调函数。这一过程确保了当通过 epoll 有数据到达时,能够调用正确的处理函数。这一环节是实现高效服务器响应的关键步骤。

       `setsockopt` 函数被用于检查网络异常后的操作,通过设置选项层次(如 SOL_SOCKET、IPPROTO_TCP 等)和特定选项的值,实现对网络连接的优化与控制。此功能的详细解释和示例请查阅相关开源社区或技术资料。

       `listener_cb` 函数是福建易达商联网站源码 uHTTPd 的关键回调函数之一,它在 epoll 事件发生时被调用,用于处理客户端连接。其后,`uh_accept_client` 函数负责实际的连接接受过程,通过 `calloc` 函数分配内存空间,并返回指向新分配内存的指针。这一步骤确保了分配的内存空间被初始化为零,为后续数据处理做好准备。

       `accept` 函数在客户端连接请求处理中扮演重要角色,它从服务器监听的 socket 中接收新的连接请求,并返回一个用于与客户端通信的新的套接字描述符。对于这一函数的具体实现和使用细节,可以参考相关技术论坛或开发者文档。

       `getsockname` 函数用于服务器端获取相关客户端的地址信息,这对于维护连接状态和进行数据传输具有重要意义。此函数的详细用法和示例可查阅相关技术资源。

       `ustream_fd_init` 函数通过回调函数 `client_ustream_read_cb` 实现客户端数据的真正读取,而 `client_ustream_read_cb` 则负责操作从客户端读取的数据,确保数据处理的高效性和准确性。

关于java的监听器

       1、public void addWindowListener(WindowListener l)添加指定的窗口侦听器,以从此窗口接收窗口事件。如果 l 为 null,则不抛出任何异常,且不执行任何操作。 

       è¿™ä¸ªæ˜¯API中的方法定义,此方法参数为接口WindowListener,任何实现该接口的类都可以作为参数。

       2、public abstract class WindowAdapter implements WindowListener, WindowStateListener, WindowFocusListener

       æŽ¥æ”¶çª—口事件的抽象适配器类。此类中的方法为空。此类存在的目的是方便创建侦听器对象。

       æ‰©å±•æ­¤ç±»å¯åˆ›å»º WindowEvent 侦听器并为所需事件重写该方法。(如果要实现

       WindowListener 接口,则必须定义该接口内的所有方法。此抽象类将所有方法都定义为

       null,所以只需针对关心的事件定义方法。)

       ä½¿ç”¨æ‰©å±•çš„类可以创建侦听器对象,然后使用窗口的 addWindowListener

       æ–¹æ³•å‘该窗口注册侦听器。当通过打开、关闭、激活或停用、图标化或取消图标化而改变了窗口状态时,将调用该侦听器对象中的相关方法,并将

       WindowEvent 传递给该方法。

       3、如果我想在代码中一次性使用某个类(抽象类或具体类)或接口,可以使用匿名类的方式,这样不需自己定义一个My***类,然后再使用,比较方便。用法就是直接在new WindowAdapter()后面加入类定义,在其中实现或覆盖方法就可以了。

       åŒ¿åç±»ä¸æ˜¯è¿”回值,而是相当于new String(“hello”)这种的扩展形式。我觉得匿名类的最多用处就是加监听器时。

       é™„上WindowAdapter源代码:

public abstract class WindowAdapter

           implements WindowListener, WindowStateListener, WindowFocusListener

       {

           public void windowOpened(WindowEvent e) { }

           public void windowClosing(WindowEvent e) { }

           public void windowClosed(WindowEvent e) { }

           public void windowIconified(WindowEvent e) { }

           public void windowDeiconified(WindowEvent e) { }

           public void windowActivated(WindowEvent e) { }

           public void windowDeactivated(WindowEvent e) { }

           public void windowStateChanged(WindowEvent e) { }

           public void windowGainedFocus(WindowEvent e) { }

           public void windowLostFocus(WindowEvent e) { }

       }

如何在ASP.NET Core 6中使用跟踪监听器

       å½“使用ASP.NET Core 6构建的应用程序时,你可能经常想使用跟踪和记录来监控你的应用程序的性能和诊断错误。你也可以在生产环境中使用跟踪来衡量你的应用程序在运行时的表现。

       è¿™ç¯‡æ–‡ç« è®¨è®ºäº†æˆ‘们如何在ASP.NET Core 6中使用追踪。我们将研究如何使用跟踪监听器来收集跟踪信息,并使用ILogger将跟踪输出引导到事件日志中。

       è¦ä½¿ç”¨æœ¬æ–‡æä¾›çš„代码示例,你的系统中应该安装有Visual Studio 。如果你还没有副本,你可以在这里下载Visual Studio 。

在Visual Studio 中创建一个ASP.NET Core Web API项目

       é¦–先,让我们在Visual Studio 中创建一个ASP.NET Core项目。按照这些步骤将在Visual Studio 中创建一个新的ASP.NET Core 6 Web API项目。

       å¯åŠ¨Visual Studio IDE。

       ç‚¹å‡» "创建新项目"。

       åœ¨ "创建新项目 "窗口,从显示的模板列表中选择 "ASP.NET Core Web API"。

       ç‚¹å‡» "下一步"。

       åœ¨ "配置你的新项目 "窗口中,指定新项目的名称和位置。

       æ ¹æ®ä½ çš„喜好,可以选择勾选 "将解决方案和项目放在同一目录下 "复选框。

       ç‚¹å‡» "下一步"。

       åœ¨æŽ¥ä¸‹æ¥æ˜¾ç¤ºçš„ "附加信息 "窗口中,确保勾选 "使用控制器... "的复选框,因为我们在这个例子中不会使用最小的API。将 "验证类型 "保留为 "无"(默认)。

       ç¡®ä¿ "启用Docker"、"为HTTPS配置 "和 "启用开放API支持 "的复选框不被选中,因为我们不会在这里使用任何这些功能。

       ç‚¹å‡»åˆ›å»ºã€‚

       æˆ‘们将使用这个ASP.NET Core 6 Web API项目,在本文的后续部分使用跟踪监听器。

什么是跟踪?

       ä¸Žè¿½è¸ªä¸»è¦äº‹ä»¶çš„事件日志相比,追踪可以更全面地了解运行中的应用程序及其组件。日志由结构化或非结构化的时间戳数据组成,显示了你的应用程序中发生的事件的记录。追踪提供了对单个请求以及它如何被处理的更多可见性。

       System.Diagnostics命名空间包含Trace和Debug类。跟踪类在生产环境中使用,而调试类在开发时使用。

       è¿½è¸ªé€šå¸¸åŒ…括以下三个阶段。

       å·¥å…·åŒ–。我们编写必要的代码来捕获相关信息

       è¿½è¸ªã€‚我们把跟踪信息写到指定的目标,即事件日志、文本文件、数据库表等。

       åˆ†æžã€‚我们分析从跟踪中收集到的信息,以确定应用程序中的瓶颈。

什么是跟踪监听器?为什么需要它们?

       è·Ÿè¸ªç›‘听器收集跟踪信息,存储它们,并将它们引导到一个适当的目标,如文本文件。.NET提供了几种跟踪监听器,包括以下几种。

       ConsoleTraceListener - 将跟踪信息发送到控制台窗口。

       DefaultTraceListener - 将跟踪信息发送到标准调试输出。

       DelimitedListTraceListener - 将跟踪输出以限定的格式发送到流、流作家或文本作家。

       EventLogTraceListener - 发送跟踪信息到事件日志。

       TextWriterTraceListener - 发送跟踪信息到一个文本文件。

       XmlWriterTraceListener - 将跟踪信息转换为XML。

       System.Diagnostics.Debug和System.Diagnostics.Trace类可以向跟踪监听器发送消息,而监听器又将消息发送到适当的目标。

在ASP.NET Core 6中使用配置文件创建一个跟踪监听器

       ä½ å¯ä»¥é€šè¿‡ä½¿ç”¨é…ç½®æ–‡ä»¶æˆ–编写自定义代码来创建一个跟踪监听器。下面显示的代码片断说明了如何使用你的应用程序配置文件创建一个跟踪监听器。

<configuration>

       æ‰€æœ‰æ·»åŠ åˆ°ç›‘听器集合中的监听器都会收到跟踪输出。然而,你可以使用一个监听器而不把它添加到监听器集合中。在这种情况下,你在监听器中使用Write或WriteLine方法发送输出。

       ä¸‹é¢çš„代码说明了一个监听器,它没有被添加到监听器集合中,但仍然能够将跟踪信息发送到输出窗口、文件或任何预先配置的输出。

TextWriterTraceListenermyFirstListener=new在ASP.NET Core 6中创建一个自定义跟踪监听器

       åœ¨å¤§å¤šæ•°æƒ…况下,.NET 6默认附带的跟踪监听器将满足您的要求。然而,如果你想把你的跟踪信息输出到不同的目的地,你可以实现你自己的跟踪监听器。

       è¦å»ºç«‹ä¸€ä¸ªè‡ªå®šä¹‰çš„跟踪监听器,你应该创建一个扩展TraceListener抽象类的类。在TraceListener类中有几个虚拟和抽象的方法。你至少应该实现Write和WriteLine方法。至少,你的自定义跟踪监听器应该看起来像这样。

publicclassCustomTraceListener:TraceListener

       æ‰€ä»¥ï¼Œä½ çš„自定义跟踪监听器类必须有一个参数构造器和Write和WriteLine方法。

       ä½ è¿˜éœ€è¦ä¸€ä¸ªILogger实例来代表记录器,一个记录器工厂来创建记录器,以及一个StringBuilder来存储跟踪消息,然后再将它们发送到日志目标。

privatereadonlyILoggerFactory_loggerFactory;

       ä½ å¯ä»¥åˆ©ç”¨ä¾èµ–注入的优势,在构造函数中注入ILoggerFactory的一个实例,然后使用该实例来创建ILogger的一个实例。

publicCustomTraceListener(ILoggerFactoryloggerFactory)

       è¿™é‡Œæ˜¯Write和WriteLine方法的一个最小实现。

publicoverridevoidWrite(string?message,string?category)ASP.NET Core 6中完整的自定义跟踪监听器示例

       ä¸‹é¢æ˜¯æˆ‘们对自定义跟踪监听器的最小实现的完整源代码,供您参考。

usingSystem.Collections.Concurrent;在Program.cs文件中注册自定义跟踪监听器

       è¦ä½¿ç”¨è‡ªå®šä¹‰è·Ÿè¸ªç›‘听器,你应该使用以下代码在监听器集合中注册它。

varloggerFactory=app.Services.GetRequiredService<ILoggerFactory>();

       å› ä¸ºæˆ‘们的自定义跟踪监听器已经被添加到监听器集合中,它将捕获所有由运行时产生的跟踪消息,并将输出发送到我们的记录器。它还将发送我们在应用程序中明确发送的任何跟踪消息(就像我们在前面的myFirstListener例子中做的那样)。

       å› æ­¤ï¼Œä»»ä½•æ·»åŠ åˆ°ç›‘听器集合的监听器都可以捕获由运行时产生的跟踪信息,以及在应用程序中明确发送的任何跟踪信息。然而,如果一个跟踪监听器没有被添加到集合中,它只能发送应用程序中明确发送的跟踪消息。它不会捕获任何由运行时产生的跟踪消息。

       å½“使用自定义跟踪监听器时,你必须记住关闭或刷新跟踪监听器,以确保输出缓冲区被清空。你可以利用StringBuilderCache类来优化你使用StringBuilder的代码(在CustomTraceListener类)。

图解+源码讲解 Nacos 客户端动态监听配置机制

       图解+源码讲解 Nacos 客户端动态监听配置机制

       在人生中第一要紧的是发现自己。为了这个目的,各位时常需要孤独和深思 —— 南森 Nacos 源码分析系列相关文章

       从零开始看 Nacos 源码环境搭建

       图解+源码讲解 Nacos 客户端发起注册流程

       图解+源码讲解 Nacos 服务端处理注册请求逻辑

       图解+源码讲解 Nacos 客户端下线流程

       图解+源码讲解 Nacos 服务端处理下线请求

       图解+源码讲解 Nacos 客户端发起心跳请求

       图解+源码讲解 Nacos 服务端处理心跳请求

       图解+源码讲解 Nacos 服务端处理配置获取请求

       图解+源码讲解 Nacos 客户端动态监听配置机制

NacosConfigAutoConfiguration

       我们看到这里面其实注入了一个 Nacos 配置刷新的关键 NacosContextRefresherBean

@Configuration@ConditionalOnProperty(name?=?"spring.cloud.nacos.config.enabled",?matchIfMissing?=?true)public?class?NacosConfigAutoConfiguration?{ //?Nacos?配置属性@Beanpublic?NacosConfigProperties?nacosConfigProperties(ApplicationContext?context)?{ if?(context.getParent()?!=?null&&?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context.getParent(),?NacosConfigProperties.class).length?>?0)?{ return?BeanFactoryUtils.beanOfTypeIncludingAncestors(context.getParent(),NacosConfigProperties.class);}return?new?NacosConfigProperties();}//?Nacos?配置刷新属性@Beanpublic?NacosRefreshProperties?nacosRefreshProperties()?{ return?new?NacosRefreshProperties();}//?Nacos?刷新历史@Beanpublic?NacosRefreshHistory?nacosRefreshHistory()?{ return?new?NacosRefreshHistory();}//?Nacos?配置管理@Beanpublic?NacosConfigManager?nacosConfigManager(NacosConfigProperties?nacosConfigProperties)?{ return?new?NacosConfigManager(nacosConfigProperties);}//?Nacos?配置刷新@Beanpublic?NacosContextRefresher?nacosContextRefresher(NacosConfigManager?nacosConfigManager,NacosRefreshHistory?nacosRefreshHistory)?{ return?new?NacosContextRefresher(nacosConfigManager,?nacosRefreshHistory);}}NacosContextRefresher 配置中心刷新public?NacosContextRefresher(NacosConfigManager?nacosConfigManager,NacosRefreshHistory?refreshHistory)?{ //?获取配置属性信息this.nacosConfigProperties?=?nacosConfigManager.getNacosConfigProperties();//?刷新历史this.nacosRefreshHistory?=?refreshHistory;//?获取配置服务this.configService?=?nacosConfigManager.getConfigService();//?是否开启刷新,是truethis.isRefreshEnabled?=?this.nacosConfigProperties.isRefreshEnabled();}获取配置服务 getConfigService

       nacosConfigManager.getConfigService(),这行代码其实就是为了创建 NcaosConfigService 对象,我们看看你是怎么创建的,其实核心代码就是通过 NacosFactory 反射创建的 NcaosConfigService 对象,这个对象是一个核心对象后续会讲到的

public?static?ConfigService?createConfigService(Properties?properties)?throws?NacosException?{ try?{ //?加载?NacosConfigService?类Class<?>?driverImplClass?=?Class.forName("com.alibaba.nacos.client.config.NacosConfigService");//?获取构造器Constructor?constructor?=?driverImplClass.getConstructor(Properties.class);//?创建实例ConfigService?vendorImpl?=?(ConfigService)?constructor.newInstance(properties);return?vendorImpl;}?catch?(Throwable?e)?{ throw?new?NacosException(NacosException.CLIENT_INVALID_PARAM,?e);}}监听器

       NacosContextRefresher 实现了 ApplicationListener ,一看这就是一个监听器了,我们看看这个在监听器里面做了什么操作

@Overridepublic?void?onApplicationEvent(ApplicationReadyEvent?event)?{ //?这是一个?CAS?操作,只设置一次if?(this.ready.compareAndSet(false,?true))?{ //?注册?Nacos?监听器对于应用this.registerNacosListenersForApplications();}}注册 Nacos 监听/**

       register Nacos Listeners. 注册Nacos监听器 */ private void registerNacosListenersForApplications() { // 默认是 true if (isRefreshEnabled()) { // 遍历Nacos属性资源中心 for (NacosPropertySource propertySource : NacosPropertySourceRepository .getAll()) { if (!propertySource.isRefreshable()) { continue; } // 获取资源ID ?String dataId = propertySource.getDataId(); // 通过组和 dataId 注册 Nacos 监听器 registerNacosListener(propertySource.getGroup(), dataId); } } }

       private void registerNacosListener(final String groupKey, final String dataKey) { // 构建 Key 信息 String key = NacosPropertySourceRepository.getMapKey(dataKey, groupKey); // 在 listenerMap中放入了 key 对应 AbstractSharedListener 响应的方法 Listener listener = listenerMap.computeIfAbsent(key, lst -> new AbstractSharedListener() { @Override public void innerReceive(String dataId, String group, String configInfo) { // 刷新次数 refreshCountIncrement(); // 记录刷新历史,就是改变历史 nacosRefreshHistory.addRefreshRecord(dataId, group, configInfo); // 发布刷新事件 applicationContext.publishEvent( new RefreshEvent(this, null, "Refresh Nacos config")); } }); // 向配置服务中添加监听器 configService.addListener(dataKey, groupKey, listener);

       }

####?向配置服务中添加监听器&nbsp;&nbsp;&nbsp;&nbsp;此时调用的是?NacosConfigService?中的?addListener?方法,但是最终执行的还是?ClientWorker?中的?addTenantListeners?方法,后面会进行分析?ClientWorker?这个类的```java@Overridepublic?void?addListener(String?dataId,?String?group,?Listener?listener)?throws?NacosException?{ //?这个?ClientWorker?worker?也是一个核心类worker.addTenantListeners(dataId,?group,?Arrays.asList(listener));}构建 CacheData 信息

       此时向 ClientWorker 中的 CacheData 中添加数据,之后遍历监听器添加到 CacheData 中

创建 CacheData 对象public?CacheData(ConfigFilterChainManager?configFilterChainManager,?String?name,?String?dataId,?String?group,String?tenant)?{ //?dataId?不能为空if?(null?==?dataId?||?null?==?group)?{ throw?new?IllegalArgumentException("dataId="?+?dataId?+?",?group="?+?group);}this.name?=?name;this.configFilterChainManager?=?configFilterChainManager;this.dataId?=?dataId;?//?设置dataIdthis.group?=?group;?//?设置组信息this.tenant?=?tenant;?//?设置租户listeners?=?new?CopyOnWriteArrayList<ManagerListenerWrap>();?//?装饰器集合this.isInitializing?=?true;//?加载缓存数据从本地磁盘this.content?=?loadCacheContentFromDiskLocal(name,?dataId,?group,?tenant);//?计算本地缓存信息的MD5this.md5?=?getMd5String(content);}向 CacheData 中添加数据public?void?addTenantListeners(String?dataId,?String?group,List<?extends?Listener>?listeners)throws?NacosException?{ //?DefaultGroupgroup?=?null2defaultGroup(group);String?tenant?=?agent.getTenant();?//?是?""//?向缓存数据中添加监听器CacheData?cache?=?addCacheDataIfAbsent(dataId,?group,?tenant);for?(Listener?listener?:?listeners)?{ cache.addListener(listener);}}public?CacheData?addCacheDataIfAbsent(String?dataId,?String?group,?String?tenant)throws?NacosException?{ //?获取Key信息String?key?=?GroupKey.getKeyTenant(dataId,?group,?tenant);//?在缓存?Map?中获取缓存数据CacheData?cacheData?=?cacheMap.get(key);//?如果不为空的情况下那么就返回,如果为空那么就创建一个?CacheDataif?(cacheData?!=?null)?{ return?cacheData;}//?创建一个?CacheData?cacheData?=?new?CacheData(configFilterChainManager,?agent.getName(),dataId,?group,?tenant);//?将创建好的?cacheData?放入缓存?Map?中CacheData?lastCacheData?=?cacheMap.putIfAbsent(key,?cacheData);//?如果缓存数据为空的话那么从配置中心拉取,不过此时不为空if?(lastCacheData?==?null)?{ //fix?issue?#?if?(enableRemoteSyncConfig)?{ String[]?ct?=?getServerConfig(dataId,?group,?tenant,?L);cacheData.setContent(ct[0]);}//?计算任务IDint?taskId?=?cacheMap.size()?/?(int)?ParamUtil.getPerTaskConfigSize();//?设置任务IDcacheData.setTaskId(taskId);lastCacheData?=?cacheData;}//?缓存数据初始化完成//?reset?so?that?server?not?hang?this?checklastCacheData.setInitializing(true);LOGGER.info("[{ }]?[subscribe]?{ }",?agent.getName(),?key);MetricsMonitor.getListenConfigCountMonitor().set(cacheMap.size());//?返回最新的缓存数据return?lastCacheData;}

       到这里 CacheData 对象 和 cacheMap 集合已经构建完成了,后续会用到这个数据的

NacosConfigService 分析

       NacosConfigService这个类在创建的时候主要做了什么事情,这这里面创建了一个 ClientWorker对象,这个对象是一个核心的类,有关于配置的一些操作都是归功于 ClientWorker类

public?NacosConfigService(Properties?properties)?throws?NacosException?{ ......this.agent?=?new?MetricsHttpAgent(new?ServerHttpAgent(properties));this.agent.start();//?核心工作类this.worker?=?new?ClientWorker(this.agent,this.configFilterChainManager,?properties);}核心配置类 ClientWorker

       分析一下这个类都在做什么事情,都有哪些核心方法 其实能看到里面有一个构造函数、添加缓存数据、添加监听器、检查配置中心相关方法、获取服务配置、解析数据响应、移除缓存数据、删除监听器以及 shutdown方法

构造函数

       看到这里其实看到了定义了两个调度线程池,一个是用于配置检测的,一个是用于执行长轮询服务的

@SuppressWarnings("PMD.ThreadPoolCreationRule")public?ClientWorker(final?HttpAgent?agent,final?ConfigFilterChainManager?configFilterChainManager,?final?Properties?properties){ this.agent?=?agent;this.configFilterChainManager?=?configFilterChainManager;//?初始化操作init(properties);//?定义一个调度线程池,只有一个线程还是守护线程this.executor?=?Executors.newScheduledThreadPool(1,?new?ThreadFactory()?{ @Overridepublic?Thread?newThread(Runnable?r)?{ Thread?t?=?new?Thread(r);t.setName("com.alibaba.nacos.client.Worker."?+?agent.getName());t.setDaemon(true);return?t;}});//?定义一个多个线程的调度线程池,线程个数和CPU?核心数有关,也是守护线程,是一个长轮询this.executorService?=?Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(),?new?ThreadFactory()?{ @Overridepublic?Thread?newThread(Runnable?r)?{ Thread?t?=?new?Thread(r);t.setName("com.alibaba.nacos.client.Worker.longPolling."?+agent.getName());t.setDaemon(true);return?t;}});//?定义一个定时的调度任务,第一次执行的时候延时1毫秒,后续毫秒调度一次this.executor.scheduleWithFixedDelay(new?Runnable()?{ @Overridepublic?void?run()?{ try?{ //?检查配置信息方法checkConfigInfo();}?catch?(Throwable?e)?{ LOGGER.error("["?+?agent.getName()?+?"]?"+?"[sub-check]?rotate?check?error",?e);}}},?1L,?L,?TimeUnit.MILLISECONDS);}检查配置服务方法

       这个 cacheMap 包含了一些任务信息,这里面的任务是怎么来的呢,他是在添加监听器的时候添加的,上面已经分析过了

public?NacosContextRefresher(NacosConfigManager?nacosConfigManager,NacosRefreshHistory?refreshHistory)?{ //?获取配置属性信息this.nacosConfigProperties?=?nacosConfigManager.getNacosConfigProperties();//?刷新历史this.nacosRefreshHistory?=?refreshHistory;//?获取配置服务this.configService?=?nacosConfigManager.getConfigService();//?是否开启刷新,是truethis.isRefreshEnabled?=?this.nacosConfigProperties.isRefreshEnabled();}0长轮询任务 LongPollingRunnable

Spring事件监听机制

       Spring事件体系包括三个组件:事件,事件监听器,事件广播器。

       1.1 事件

       1.1.1 Spring内置事件

       1.1.2 自定义事件

       事件类需要继承ApplicationEvent,代码如下:

       这里为了简单测试,所以写的很简单。

       事件类是一种很简单的pojo,除了需要继承ApplicationEvent也没什么了,这个类有一个构造方法需要super。

       1.2 事件监听器

       1.2.1 事件监听器-基于接口

       1.2.2 事件监听器-基于注解

       1.3 事件发布操作

       事件发布方式很简单

       然后调用方法就能看到

       疑问

       同样的事件能有多个监听器吗 -- 可以的

       事件监听器一定要写一个类去实现吗 -- 其实是可以不需要的,spring有个注解@EventListener,修饰在方法上,稍后给出使用方法

       事件监听操作和发布事件的操作是同步的吗? -- 是的,所以如果有事务,监听操作也在事务内

       可以作为异步处理吗? --可以 看源码有解释。

       1.4 Spring事件原理

       原理:观察者模式

       spring的事件监听有三个部分组成:

       事件(ApplicationEvent) 负责对应相应监听器 事件源发生某事件是特定事件监听器被触发的原因。

       监听器(ApplicationListener) 对应于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑。

       事件发布器(ApplicationEventMulticaster )对应于观察者模式中的被观察者/主题, 负责通知观察者 对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器。

       Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者,工作流程如下:

       Spring事件机制

       也就是说上面代码中发布者调用applicationEventPublisher.publishEvent(msg); 是会将事件发送给了EventMultiCaster, 而后由EventMultiCaster注册着所有的Listener,然后根据事件类型决定转发给那个Listener。

       二、源码流程

       2.1 源码流程

       Spring在ApplicationContext接口的抽象实现类AbstractApplicationContext中完成了事件体系的搭建。

       2.2 事件广播器的初始化

       2.3 注册事件监听器

       2.4 发布事件

       2.5 Spring默认的事件广播器SimpleApplicationEventMulticaster

       从代码可以看出,applicationContext.publishEvent()方法,需要同步等待各个监听器处理完之后,才返回。

       也就是说,Spring提供的事件机制,默认是同步的。如果想用异步的,可以自己实现ApplicationEventMulticaster接口,并在Spring容器中注册id为applicationEventMulticaster的Bean。

       Spring发布事件之后,所有注册的事件监听器,都会收到该事件,因此,事件监听器在处理事件时,需要先判断该事件是否是自己关心的。

       Sping事件体系所使用的设计模式是:观察者模式。ApplicationListener是观察者接口,接口中定义了onApplicationEvent方法,该方法的作用是对ApplicationEvent事件进行处理。

       三、看几个问题

       3.1 怎么样可以在所有Bean创建完后做扩展代码?

       第一种:使用spring内置事件ContextRefreshedEvent

       第二种:通过实现SmartInitializingSingleton接口重写afterSingletonsInstantiated()方法

       3.2 请介绍下Spring事件监听器的原理。

       原理:观察者模式

       spring的事件监听有三个部分组成:

       事件(ApplicationEvent) 负责对应相应监听器 事件源发生某事件是特定事件监听器被触发的原因。

       监听器(ApplicationListener) 对应于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑。

       事件发布器(ApplicationEventMulticaster )对应于观察者模式中的被观察者/主题, 负责通知观察者 对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器。

       Spring事件机制是观察者模式的一种实现,但是除了发布者和监听者者两个角色之外,还有一个EventMultiCaster的角色负责把事件转发给监听者,工作流程如下:

       Spring事件机制

       也就是说上面代码中发布者调用applicationEventPublisher.publishEvent(msg); 是会将事件发送给了EventMultiCaster, 而后由EventMultiCaster注册着所有的Listener,然后根据事件类型决定转发给那个Listener。