1.ListenableFuture源码解析
2.图解+源码讲解 Nacos 客户端动态监听配置机制
3.Nginx源码分析—HTTP模块之TCP连接建立过程详解
4.串口监听到的监听解析监听解析数据如何解析?
5.一文详解RocketMQ-Spring的源码解析与实战
ListenableFuture源码解析
ListenableFuture 是 spring 中对 JDK Future 接口的扩展,主要应用于解决在提交线程池的源码源码任务拿到 Future 后在 get 方法调用时会阻塞的问题。通过使用 ListenableFuture,监听解析监听解析可以向其注册回调函数(监听器),源码源码当任务完成时,监听解析监听解析触发回调。源码源码趣步现成源码Promise 在 Netty 中也实现了类似的监听解析监听解析功能,用于处理类似 Future 的源码源码场景。
实现 ListenableFuture 的监听解析监听解析关键在于 FutureTask 的源码解析。FutureTask 是源码源码实现 Future 接口的基础类,ListenableFutureTask 在其基础上做了扩展。监听解析监听解析其主要功能是源码源码在任务提交后,当调用 get 方法时能够阻塞当前业务线程,监听解析监听解析直到任务完成时唤醒。源码源码
FutureTask 通过在内部实现一个轻量级的监听解析监听解析 Treiber stack 数据结构来管理等待任务完成的线程。这个数据结构由 WaitNode 节点组成,每个节点代表一个等待的flash项目源码线程。当业务线程调用 get 方法时,会将自己插入到 WaitNode 栈中,并且在插入的同时让当前线程进入等待状态。在任务执行完成后,会遍历 WaitNode 栈,唤醒等待的线程。
为了确保并发安全,FutureTask 使用 CAS(Compare and Swap)操作来管理 WaitNode 栈。每个新插入的节点都会使用 CAS 操作与栈顶节点进行比较,并在满足条件时更新栈顶。这一过程保证了插入操作的原子性,防止了并发条件下的数据混乱。同时,插入操作与栈顶节点的更新操作相互交织,确保了数据的一致性和完整性。
在 FutureTask 中,二十影院源码还利用了 LockSupport 类提供的 park 和 unpark 方法来实现线程的等待和唤醒。当线程插入到 WaitNode 栈中后,通过 park 方法将线程阻塞;任务执行完成后,通过 unpark 方法唤醒线程,完成等待与唤醒的流程。
综上所述,ListenableFuture 通过扩展 FutureTask 的功能,实现了任务执行与线程等待的高效管理。通过注册监听器并利用 CAS 操作与 LockSupport 方法,实现了在任务完成时通知回调,解决了异步任务执行时的线程阻塞问题,提高了程序的并发处理能力。
图解+源码讲解 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();}获取配置服务 getConfigServicenacosConfigManager.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);
}
####?向配置服务中添加监听器 此时调用的是?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长轮询任务 LongPollingRunnableNginx源码分析—HTTP模块之TCP连接建立过程详解
Nginx源码中HTTP模块的TCP连接建立过程详细解析如下:
首先,监听套接字的初始化由ngx_http_optimize_servers函数负责,这个函数在HTTP模块的初始化过程中起关键作用,通过ngx_http_init_listening和ngx_http_add_listening函数创建并设置监听套接字,根据服务器配置的每个IP地址和端口进行。
在main函数的ngx_init_cycle()中,通过ngx_open_listening_sockets调用了一系列设置,包括非阻塞模式、缓冲区大小、绑定和监听等。HTTP模块的优先级高于Event模块,HTTP模块初始化后,会调用ngx_http_init_connection,为每个客户端连接设置初始化处理函数。
Event模块的初始化则通过ngx_event_process_init函数,每个worker进程都会调用它,设置接收连接的回调函数为ngx_event_accept。当客户端连接时,Nginx会进入事件循环,检测到读事件会调用ngx_event_accept,进一步处理连接请求。
调用ngx_event_accept后,会创建ngx_connection_t结构,并将最初的读取事件回调改为ngx_http_wait_request_handler,后续的客户端读取事件都将通过这个函数处理。这意味着ngx_http_wait_request_handler成为了HTTP模块数据处理的入口点。
整个连接过程可以用以下流程图概括:
1. 初始化监听套接字
2. 设置套接字选项和回调函数
3. 客户端连接时,调用ngx_event_accept
4. ngx_http_init_connection处理连接并修改回调
5. 客户端读取事件通过ngx_http_wait_request_handler处理
以上是Nginx连接建立过程的核心步骤。
串口监听到的数据如何解析?
如果您想从串口监听到的数据进行解析,您可以使用以下方法:
1. 使用 API:许多第三方编程语言提供了串口 API,您可以使用这些 API来监听到的数据。例如,如果您想获取文件的位置和大小信息,您可以使用 FastStack API来读取文件并将其作为数据输入到代码中。
2. 使用函数:如果您想从串口监听到的数据中提取出某些特定的函数,你可以使用串口监听到的数据编写函数来实现。例如,如果您想获取文件的位置和大小信息,可以使用 RemotingExpectation函数来实现。
3. 使用接口:有些第三方编程语言提供了一个专门用于处理串口监听到的数据的接口,例如 FastStack API、 FastStack Framework或 FrameworkTool。如果您想了解这些接口的细节,请阅读源代码或联系相关专业人员。
请注意,有些 API可能会对串口监听到的数据进行某些处理,因此在使用前请仔细阅读说明书或咨询专业人员。
(#以上仅供参考)
一文详解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设计思路和源码理解四个方面逐步提升。