<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Docs on 知识铺的博客</title>
    <link>https://index.zshipu.com/geek/tags/docs/</link>
    <description>Recent content in Docs on 知识铺的博客</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-CN</language>
    <lastBuildDate>Wed, 06 Mar 2024 13:58:00 +0000</lastBuildDate>
    <atom:link href="https://index.zshipu.com/geek/tags/docs/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>rocketmq-send-store</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-send-store/</link>
      <pubDate>Wed, 06 Mar 2024 13:58:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-send-store/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ 消息发送存储流程 第一步：检查消息存储状态 org.apache.rocketmq.store.DefaultMessageStore#checkStoreStatus 1、检查 broker 是否可用 1 2 3 4 if (this.shutdown) { log.warn(&amp;#34;message store has shutdown, so putMessage is forbidden&amp;#34;); return PutMessageStatus.SERVICE_NOT_AVAILABLE; } 2、检查 broker 的角色 1 2 3 4 5 6 7 if (BrokerRole.SLAVE== this.messageStoreConfig.getBrokerRole()) { long value = this.printTimes.getAndIncrement(); if ((value % 50000) == 0) { log.warn(&amp;#34;broke role is slave, so putMessage is forbidden&amp;#34;); } return PutMessageStatus.SERVICE_NOT_AVAILABLE; } 3、检查 messageStore 是否可写 1 2 3 4 5 6 7 8 9 10 if (!this.runningFlags.isWriteable()) { long value = this.printTimes.getAndIncrement(); if ((value % 50000) ==</description>
    </item>
    <item>
      <title>rocketmq-send-message</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-send-message/</link>
      <pubDate>Wed, 06 Mar 2024 13:57:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-send-message/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ 消息发送流程 这里以同步发送为示例讲解： 入口： org.apache.rocketmq.client.producer.DefaultMQProducer#send(org.apache.rocketmq.common.message.Message) 消息发送 默认超时时间 3 秒 第一步：验证 主题的长度不能大于 127，消息的大小不能大于 4M 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public static void checkMessage(Message msg, DefaultMQProducer defaultMQProducer) throws MQClientException { if (null == msg) { throw new MQClientException(ResponseCode.MESSAGE_ILLEGAL, &amp;#34;the message is null&amp;#34;); } // topic Validators.checkTopic(msg.getTopic()); Validators.isNotAllowedSendTopic(msg.getTopic()); // body if (null == msg.getBody()) { throw</description>
    </item>
    <item>
      <title>rocketmq-pullmessage</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-pullmessage/</link>
      <pubDate>Wed, 06 Mar 2024 13:56:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-pullmessage/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ 消息拉取流程 之前在消费者启动流程中描述过 MQClientInstance 的启动流程，在启动过程中会启动 PullMessageService，它继承了ServiceThread，并且 ServiceThread 实现了 Runnable 接口，所以是单独启动了一个线程 public class PullMessageService extends ServiceThread public abstract class ServiceThread implements Runnable PullMessageService 的 run 方法如下： protected volatile boolean stopped = false; 1</description>
    </item>
    <item>
      <title>rocketmq-pullmessage-processor</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-pullmessage-processor/</link>
      <pubDate>Wed, 06 Mar 2024 13:55:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-pullmessage-processor/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ broker 处理拉取消息请求流程 org.apache.rocketmq.broker.processor.PullMessageProcessor#processRequest(io.netty.channel.ChannelHandlerContext, org.apache.rocketmq.remoting.protocol.RemotingCommand) 第 1 步、校验broker是否可读 1 2 3 4 5 if (!PermName.isReadable(this.brokerController.getBrokerConfig().getBrokerPermission())) { response.setCode(ResponseCode.NO_PERMISSION); response.setRemark(String.format(&amp;#34;the broker[%s] pulling message is forbidden&amp;#34;, this.brokerController.getBrokerConfig().getBrokerIP1())); return response; } 第 2 步、根据消费组获取订阅信息 1 2 SubscriptionGroupConfig subscriptionGroupConfig = this.brokerController.getSubscriptionGroupManager().findSubscriptionGroupConfig(requestHeader.getConsumerGroup()); 第 3 步、校验是否允许消费 1 2 3 4 5 if (!subscriptionGroupConfig.isConsumeEnable()) { response.setCode(ResponseCode.NO_PERMISSION); response.setRemark(&amp;#34;subscription group no permission, &amp;#34; + requestHeader.getConsumerGroup()); return response; } 第 4 步、根据主题获取对应的配置信息 1 2 3 4</description>
    </item>
    <item>
      <title>rocketmq-producer-start</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-producer-start/</link>
      <pubDate>Wed, 06 Mar 2024 13:54:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-producer-start/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ 生产者启动流程 入口： org.apache.rocketmq.client.producer.DefaultMQProducer#start 1 2 3 4 5 6 7 8 9 10 11 12 @Override public void start() throws MQClientException { this.setProducerGroup(withNamespace(this.producerGroup)); this.defaultMQProducerImpl.start(); if (null != traceDispatcher) { try { traceDispatcher.start(this.getNamesrvAddr(), this.getAccessChannel()); } catch (MQClientException e) { log.warn(&amp;#34;trace dispatcher start failed &amp;#34;, e); } } } 第一步、检查 producerGroup 1 2 3 4 5 6 7 8 9 10 11 private void checkConfig() throws MQClientException { Validators.checkGroup(this.defaultMQProducer.getProducerGroup()); if (null == this.defaultMQProducer.getProducerGroup()) { throw new MQClientException(&amp;#34;producerGroup is null&amp;#34;, null); } if (this.defaultMQProducer.getProducerGroup().equals(MixAll.DEFAULT_PRODUCER_GROUP)) { throw new MQClientException(&amp;#34;producerGroup can not equal &amp;#34; + MixAll.DEFAULT_PRODUCER_GROUP + &amp;#34;, please specify another one.&amp;#34;,null); } } 第二步、设置 instanceName 1 2</description>
    </item>
    <item>
      <title>rocketmq-nameserver-broker</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-nameserver-broker/</link>
      <pubDate>Wed, 06 Mar 2024 13:53:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-nameserver-broker/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RockerMQ Nameserver 如何与 Broker 进行通信的？ nameserver 每隔 10s 扫描一次 Broker，移除处于未激活状态的 Broker 核心代码： this.scheduledExecutorService.scheduleAtFixedRate(NamesrvController.this.routeInfoManager::scanNotActiveBroker, 5, 10, TimeUnit.*SECONDS*); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public int scanNotActiveBroker() { int removeCount = 0; Iterator&amp;lt;Entry&amp;lt;String, BrokerLiveInfo&amp;gt;&amp;gt; it = this.brokerLiveTable.entrySet().iterator(); while (it.hasNext()) { Entry&amp;lt;String, BrokerLiveInfo&amp;gt; next = it.next(); long last = next.getValue().getLastUpdateTimestamp(); if ((last +BROKER_CHANNEL_EXPIRED_TIME) &amp;lt; System.currentTimeMillis()) { RemotingUtil.closeChannel(next.getValue().getChannel()); it.remove(); log.warn(&amp;#34;The broker channel expired, {} {}ms&amp;#34;, next.getKey(),BROKER_CHANNEL_EXPIRED_TIME); this.onChannelDestroy(next.getKey(), next.getValue().getChannel()); removeCount++; } } return removeCount; } broker 每隔 30 秒会向集群</description>
    </item>
    <item>
      <title>rocketmq-mappedfile-detail</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-mappedfile-detail/</link>
      <pubDate>Wed, 06 Mar 2024 13:52:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-mappedfile-detail/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ MappedFile 内存映射文件详解 1、MappedFile 初始化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 private void init(final String fileName, final int fileSize) throws IOException { this.fileName = fileName; this.fileSize = fileSize; this.file = new File(fileName); this.fileFromOffset = Long.parseLong(this.file.getName()); boolean ok = false; ensureDirOK(this.file.getParent()); try { this.fileChannel = new RandomAccessFile(this.file, &amp;#34;rw&amp;#34;).getChannel(); this.mappedByteBuffer = this.fileChannel.map(MapMode.READ_WRITE, 0, fileSize); TOTAL_MAPPED_VIRTUAL_MEMORY.addAndGet(fileSize); TOTAL_MAPPED_FILES.incrementAndGet(); ok = true; } catch (FileNotFoundException e) { log.error(&amp;#34;Failed to create file &amp;#34; + this.fileName, e); throw e; } catch (IOException e) { log.error(&amp;#34;Failed to map file</description>
    </item>
    <item>
      <title>rocketmq-indexfile</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-indexfile/</link>
      <pubDate>Wed, 06 Mar 2024 13:51:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-indexfile/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ IndexFile 详解 首先明确一下 IndexFile 的文件结构 Index header + 哈希槽，每个槽下面挂载 index 索引,类似哈希表的结构 一个 Index 文件默认包含 500 万个哈希槽，一个哈希槽最多存储 4 个 index，也就是一个 IndexFile 默认最多包含 2000 万个 index Index header： 40byte Index header = 8byte 的 beginTimestamp（In</description>
    </item>
    <item>
      <title>rocketmq-consumer-start</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-consumer-start/</link>
      <pubDate>Wed, 06 Mar 2024 13:50:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-consumer-start/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ 消费者启动流程 org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl#start 1、检查配置信息 org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl#checkConfig 校验消费组的长度不能大于 255 public static final int CHARACTER_MAX_LENGTH = 255; 1 2 3 if (group.length() &amp;gt;CHARACTER_MAX_LENGTH) { throw new MQClientException(&amp;#34;the specified group is longer than group max length 255.&amp;#34;, null); } 消费组名称只能包含数字、字母、%、-、_、| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // regex: ^[%|a-zA-Z0-9_-]+$ // % VALID_CHAR_BIT_MAP[&amp;#39;%&amp;#39;] = true; // - VALID_CHAR_BIT_MAP[&amp;#39;-&amp;#39;] = true; // _ VALID_CHAR_BIT_MAP[&amp;#39;_&amp;#39;] = true; // |</description>
    </item>
    <item>
      <title>rocketmq-consumequeue</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-consumequeue/</link>
      <pubDate>Wed, 06 Mar 2024 13:49:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-consumequeue/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ ConsumeQueue 详解 RocketMQ 基于主题订阅模式实现消息消费，消费者关注每一个主题下的所有消息，但是同一主题下的消息是不连续地存储在 CommitLog 文件中的，如果消费者直接从消息存储文件中遍历查找主题下的消息，效率会特别低。所以为了在查找消息的时候效率更高一些，设计了 ConsumeQueue 文件，可以</description>
    </item>
    <item>
      <title>rocketmq-consume-message-process</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-consume-message-process/</link>
      <pubDate>Wed, 06 Mar 2024 13:48:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-consume-message-process/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ 消息消费流程 拉取消息 成功之后 会调用 org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService#submitConsumeRequest 组装 消费消息 请求 获取 consumeMessageBatchMaxSize,表示一个 ConsumeRequest 包含的消息 数量，默认为 1 入参 msgs 为拉取消息的最大值，默认为 32 如果 msgs 小于等于 consumeMessageBatchMaxSiz</description>
    </item>
    <item>
      <title>rocketmq-commitlog</title>
      <link>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-commitlog/</link>
      <pubDate>Wed, 06 Mar 2024 13:47:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/rocketmq/rocketmq-commitlog/</guid>
      <description>该文所涉及的 RocketMQ 源码版本为 4.9.3。 RocketMQ CommitLog 详解 commitlog 目录主要存储消息，为了保证性能，顺序写入，每一条消息的长度都不相同，每条消息的前面四个字节存储该条消息的总长度，每个文件大小默认为 1G，文件的命名是以 commitLog 起始偏移量命名的，可以通过修改 broker 配置文件中 mappedFileSizeCommitLog 属性改变文件大小 1、获取最小偏移量 org.apache.rocketmq.store.CommitLog#getMinOffset 1</description>
    </item>
    <item>
      <title>nacos-discovery</title>
      <link>https://index.zshipu.com/geek/post/code/docs/nacos/nacos-discovery/</link>
      <pubDate>Wed, 06 Mar 2024 13:46:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/nacos/nacos-discovery/</guid>
      <description>Nacos 服务注册 nacos-spring-boot-project 中有关服务注册的几个项目 nacos-discovery-spring-boot-actuator nacos-discovery-spring-boot-autoconfigure nacos-discovery-spring-boot-starter 1 2 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.alibaba.boot.nacos.discovery.autoconfigure.NacosDiscoveryAutoConfiguration 找到类 NacosDiscoveryAutoConfiguration 1 2 3 4 5 6 7 8 9 10 11 12 13 @ConditionalOnProperty(name = NacosDiscoveryConstants.ENABLED, matchIfMissing = true) @ConditionalOnMissingBean(name = DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME) @EnableNacosDiscovery @EnableConfigurationProperties(value = NacosDiscoveryProperties.class) @ConditionalOnClass(name = &amp;#34;org.springframework.boot.context.properties.bind.Binder&amp;#34;) public class NacosDiscoveryAutoConfiguration { @Bean public NacosDiscoveryAutoRegister discoveryAutoRegister() { return new NacosDiscoveryAutoRegister(); } } 注解:EnableNacosDiscovery 1 2 3 4 5 @Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(NacosDiscoveryBeanDefinitionRegistrar.class) public @interface EnableNacosDiscovery {} import 类 :NacosDiscoveryBeanDefinitionRegistrar 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26</description>
    </item>
    <item>
      <title>一个简单的servlet容器代码设计</title>
      <link>https://index.zshipu.com/geek/post/code/docs/Tomcat/%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84servlet%E5%AE%B9%E5%99%A8%E4%BB%A3%E7%A0%81%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Wed, 06 Mar 2024 13:45:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/Tomcat/%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84servlet%E5%AE%B9%E5%99%A8%E4%BB%A3%E7%A0%81%E8%AE%BE%E8%AE%A1/</guid>
      <description>一个简单的 Servlet 容器代码设计 Servlet 算是 Java Web 开发请求链路调用栈中底层的一个技术，当客户端发起一个请求后，到达服务器内部，就会先进入 Servlet（这里不讨论更底层的链路），SpringMVC 的请求分发核心也是一个 Servlet，名叫DispatcherServlet，一个请求首先会进入到这</description>
    </item>
    <item>
      <title>一个简单的Web服务器代码设计</title>
      <link>https://index.zshipu.com/geek/post/code/docs/Tomcat/%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84Web%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%BB%A3%E7%A0%81%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Wed, 06 Mar 2024 13:44:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/Tomcat/%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84Web%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%BB%A3%E7%A0%81%E8%AE%BE%E8%AE%A1/</guid>
      <description>一个简单的 Web 服务器代码设计 在这篇博客中，我们将介绍如何使用 Java 编写一个简单的 Web 服务器。这个 Web 服务器可以接收客户端的 HTTP 请求，并返回一个静态的 HTML 页面。 1. 代码设计 首先，我们需要创建一个 WebServer 类，这个类将负责接收客户端的请求，并返回响应。以下是 WebServer 类的代码： 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19</description>
    </item>
    <item>
      <title>servlet容器详解</title>
      <link>https://index.zshipu.com/geek/post/code/docs/Tomcat/servlet%E5%AE%B9%E5%99%A8%E8%AF%A6%E8%A7%A3/</link>
      <pubDate>Wed, 06 Mar 2024 13:43:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/Tomcat/servlet%E5%AE%B9%E5%99%A8%E8%AF%A6%E8%A7%A3/</guid>
      <description>Servlet 容器详解 Servlet 容器是 Java Web 应用程序的核心组件之一。它负责管理 Servlet 的生命周期、请求分发、会话跟踪等任务。在这篇博客中，我们将详细介绍 Servlet 容器的工作原理和常见实现。 1. Servlet 容器的工作原理 Servlet 容器的工作原理如下： 接收客户端请求：Servlet 容器监听一个或多个端口，等待客户端的请求。 解析请求：Ser</description>
    </item>
    <item>
      <title>servlet-api源码赏析</title>
      <link>https://index.zshipu.com/geek/post/code/docs/Tomcat/servlet-api%E6%BA%90%E7%A0%81%E8%B5%8F%E6%9E%90/</link>
      <pubDate>Wed, 06 Mar 2024 13:42:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/Tomcat/servlet-api%E6%BA%90%E7%A0%81%E8%B5%8F%E6%9E%90/</guid>
      <description>Servlet 基础 Servlet 简介 Servlet（Server Applet）是 J2EE 的内容之一，由 Java 编写的服务器端小程序。它是 web 请求的入口，主要功能在于交互式地（Request 和 Response）浏览和修改数据，生成动态 Web 内容。Servlet 运行于支持 Servlet 的 WEB 容器中，如 Tomcat。从实现上讲，Servle</description>
    </item>
    <item>
      <title>SpringSecurity请求全过程解析</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringSecurity/SpringSecurity%E8%AF%B7%E6%B1%82%E5%85%A8%E8%BF%87%E7%A8%8B%E8%A7%A3%E6%9E%90/</link>
      <pubDate>Wed, 06 Mar 2024 13:41:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringSecurity/SpringSecurity%E8%AF%B7%E6%B1%82%E5%85%A8%E8%BF%87%E7%A8%8B%E8%A7%A3%E6%9E%90/</guid>
      <description>Spring Security 请求全过程解析 Spring Security 是一款基于 Spring 的安全框架，主要包含认证和授权两大安全模块，和另外一款流行的安全框架 Apache Shiro 相比，它拥有更为强大的功能。Spring Security 也可以轻松的自定义扩展以满足各种需求，并且对常见的 Web 安全攻击提供了防护支持。如果你的 Web 框架选择的是 Spring，那么在安全方面 Spring Security 会</description>
    </item>
    <item>
      <title>SpringSecurity自定义用户认证</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringSecurity/SpringSecurity%E8%87%AA%E5%AE%9A%E4%B9%89%E7%94%A8%E6%88%B7%E8%AE%A4%E8%AF%81/</link>
      <pubDate>Wed, 06 Mar 2024 13:40:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringSecurity/SpringSecurity%E8%87%AA%E5%AE%9A%E4%B9%89%E7%94%A8%E6%88%B7%E8%AE%A4%E8%AF%81/</guid>
      <description>Spring Security 自定义用户认证 在Spring Boot 中开启 Spring Security一节中我们简单地搭建了一个 Spring Boot + Spring Security 的项目，其中登录页、用户名和密码都是由 Spring Security 自动生成的。Spring Security 支持我们自定义认证的过程，如使用自定义的登录页替换默认的登录页，用户信息的获取逻辑、登录成功或失败后的处理逻辑等。这里</description>
    </item>
    <item>
      <title>SpringSecurity流程补充</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringSecurity/SpringSecurity%E6%B5%81%E7%A8%8B%E8%A1%A5%E5%85%85/</link>
      <pubDate>Wed, 06 Mar 2024 13:39:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringSecurity/SpringSecurity%E6%B5%81%E7%A8%8B%E8%A1%A5%E5%85%85/</guid>
      <description>SpringSecurity 流程补充 注意: 基于 spring-boot-dependencies:2.7.7 首先需要了解 springboot2.7 升级 Changes to Auto-configuration 以后使用 autoconfigure 进行自动注入 代码地址 io.github.poo0054 启动 我们每次添加 &amp;lt;artifactId&amp;gt;spring-boot-starter-security&amp;lt;/artifactId&amp;gt;，启动的时候会有一条类似的日志： Using generated springSecurity password: 1db8eb87-e2ee-4c72-88e7-9b85268c4430 This generated password is for development use</description>
    </item>
    <item>
      <title>spring-cloud-openfeign-source-note</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringCloud/spring-cloud-openfeign-source-note/</link>
      <pubDate>Wed, 06 Mar 2024 13:38:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringCloud/spring-cloud-openfeign-source-note/</guid>
      <description>说明 源码阅读仓库: spring-cloud-openfeign 参考资料和需要掌握的知识： SpringBoot 源码分析 Spring 源码分析 Spring Cloud 官网文档 Spring Cloud Commons 官网文档 Spring Cloud OpenFeign 官网文档 Feign 官方文档 Spring Cloud OpenFeign 介绍 Feign 是一个声明式的 Web 服务客户端，它使 Java 编写 Web 服务客户端变得更加容易。其实就是通过 JDK 代理生成接口的代理对象，方法的执行就是执行 Http 请求。而 OpenFeign 的作用是通过自动装配</description>
    </item>
    <item>
      <title>spring-cloud-gateway-source-note</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringCloud/spring-cloud-gateway-source-note/</link>
      <pubDate>Wed, 06 Mar 2024 13:37:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringCloud/spring-cloud-gateway-source-note/</guid>
      <description>说明 源码阅读仓库: spring-cloud-gateway 参考资料和需要掌握的知识： Spring WebFlux 源码分析 Spring Cloud Circuit Breaker Spring Cloud Commons Spring Cloud Gateway 官网文档 Spring Cloud Gateway 介绍 功能：接收请求并根据匹配的路由进行转发。 术语： Route: 是路由规则的描述。它由 ID、目标 URI、Predicate 集合和Filter 集合组成。如果 Predicate 为真，则路由匹配。 Predicate: 这是一个 Java 8 函数接口。输</description>
    </item>
    <item>
      <title>spring-cloud-commons-source-note</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringCloud/spring-cloud-commons-source-note/</link>
      <pubDate>Wed, 06 Mar 2024 13:36:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringCloud/spring-cloud-commons-source-note/</guid>
      <description>说明 源码阅读仓库: spring-cloud-commons 参考资料和需要掌握的知识： SpringBoot 源码分析 Spring 源码分析 Spring Cloud 官网文档 Spring Cloud Commons 官网文档 Spring Cloud 介绍 SpringCloud 是在 SpringBoot 的基础上构建的。Spring Cloud 以两个库的形式提供了许多特性：Spring Cloud Context 和 Spring Cloud Commons。Spring Cloud Context 为 SpringCloud 应用程序的 ApplicationContext 提供扩展机制（引导上下文、加密、刷新属性和</description>
    </item>
    <item>
      <title>SpringBootBatch源码</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringBootBatch/SpringBootBatch%E6%BA%90%E7%A0%81/</link>
      <pubDate>Wed, 06 Mar 2024 13:35:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringBootBatch/SpringBootBatch%E6%BA%90%E7%A0%81/</guid>
      <description>SpringBootBatch 源码 加载 版本使用 2.7.13 1 2 3 4 5 6 7 &amp;lt;dependency&amp;gt; &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt; &amp;lt;artifactId&amp;gt;spring-boot-dependencies&amp;lt;/artifactId&amp;gt; &amp;lt;version&amp;gt;2.7.13&amp;lt;/version&amp;gt; &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt; &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt; &amp;lt;/dependency&amp;gt; spring-autoconfigure-metadata.properties 1 2 3 4 5 6 7 8 9 10 11 12 13 org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration= org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration$DataSourceInitializerConfiguration= org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration$DataSourceInitializerConfiguration.ConditionalOnBean=javax.sql.DataSource org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration$DataSourceInitializerConfiguration.ConditionalOnClass=org.springframework.jdbc.datasource.init.DatabasePopulator org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration.ConditionalOnBean=org.springframework.batch.core.launch.JobLauncher org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration.ConditionalOnClass=javax.sql.DataSource,org.springframework.batch.core.launch.JobLauncher org.springframework.boot.autoconfigure.batch.BatchConfigurerConfiguration= org.springframework.boot.autoconfigure.batch.BatchConfigurerConfiguration$JpaBatchConfiguration= org.springframework.boot.autoconfigure.batch.BatchConfigurerConfiguration$JpaBatchConfiguration.ConditionalOnBean= org.springframework.boot.autoconfigure.batch.BatchConfigurerConfiguration$JpaBatchConfiguration.ConditionalOnClass=javax.persistence.EntityManagerFactory org.springframework.boot.autoconfigure.batch.BatchConfigurerConfiguration.ConditionalOnBean=javax.sql.DataSource org.springframework.boot.autoconfigure.batch.BatchConfigurerConfiguration.ConditionalOnClass=org.springframework.transaction.PlatformTransactionManager @EnableBatchProcessing 启动首先添加@EnableBatchProcessing，这个类引入了BatchConfigurationSelector. BatchConfigurationSelector 这里面主要是判断modular决定加载Modula</description>
    </item>
    <item>
      <title>SpringBoot-自动装配</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringBoot/SpringBoot-%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D/</link>
      <pubDate>Wed, 06 Mar 2024 13:34:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringBoot/SpringBoot-%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D/</guid>
      <description>Spring Boot 自动装配 Author: HuiFer 源码阅读仓库: SourceHot-spring-boot org.springframework.boot.autoconfigure.SpringBootApplication 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { @AliasFor(annotation = EnableAutoConfiguration.class) Class&amp;lt;?&amp;gt;[] exclude() default {}; @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {}; @AliasFor(annotation = ComponentScan.class, attribute = &amp;#34;basePackages&amp;#34;) String[] scanBasePackages() default {}; @AliasFor(annotation = ComponentScan.class, attribute = &amp;#34;basePackageClasses&amp;#34;) Class&amp;lt;?&amp;gt;[] scanBasePackageClasses() default {}; @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; } EnableAutoConfiguration 1 2 3 4 5 6 7 8 9 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { } AutoConfigurationImportSelector 类图 getAutoConfigurationMetadata() 1 2 3 4</description>
    </item>
    <item>
      <title>SpringBoot-application-load</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringBoot/SpringBoot-application-load/</link>
      <pubDate>Wed, 06 Mar 2024 13:33:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringBoot/SpringBoot-application-load/</guid>
      <description>Spring Boot application 文件加载 Author: HuiFer 源码阅读仓库: SourceHot-spring-boot 如何找到这个加载的过程 创建配置文件application.yml 全局搜索 yml 换成properties搜索 我们以yml为例打上断点开始源码追踪 看到调用堆栈 一步一步回上去看如何调用具体方法的 ConfigFileApplicationListener 配置文件监听器 调用过程 org.springframework.boot.context.config.ConfigFileApplicationListener#addPropertySources 1 2 3 4 5 protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { RandomValuePropertySource.addToEnvironment(environment); // 加载器加</description>
    </item>
    <item>
      <title>SpringBoot-LogSystem</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringBoot/SpringBoot-LogSystem/</link>
      <pubDate>Wed, 06 Mar 2024 13:32:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringBoot/SpringBoot-LogSystem/</guid>
      <description>SpringBoot 日志系统 Author: HuiFer 源码阅读仓库: SourceHot-spring-boot 包路径: org.springframework.boot.logging 日志级别 日志级别: org.springframework.boot.logging.LogLevel 1 2 3 public enum LogLevel { TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF } Java 日志实现 org.springframework.boot.logging.java.JavaLoggingSystem 1 2 3 4 5 6 7 8 9 10 static { // KEY : springBoot 定义的日志级别, value: jdk 定义的日志级别 LEVELS.map(LogLevel.TRACE, Level.FINEST); LEVELS.map(LogLevel.DEBUG, Level.FINE); LEVELS.map(LogLevel.INFO, Level.INFO); LEVELS.map(LogLevel.WARN, Level.WARNING); LEVELS.map(LogLevel.ERROR, Level.SEVERE); LEVELS.map(LogLevel.FATAL, Level.SEVERE); LEVELS.map(LogLevel.OFF, Level.OFF); } LEVELS 对象 1 2 3 4 5 6 7 8 9 10 protected static class LogLevels&amp;lt;T&amp;gt; { /** * key ： SpringBoot 中定义的日志级别, value: 其他日志框架的日</description>
    </item>
    <item>
      <title>SpringBoot-ConfigurationProperties</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringBoot/SpringBoot-ConfigurationProperties/</link>
      <pubDate>Wed, 06 Mar 2024 13:31:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringBoot/SpringBoot-ConfigurationProperties/</guid>
      <description>SpringBoot ConfigurationProperties Author: HuiFer 源码阅读仓库: SourceHot-spring-boot 本文主要对org.springframework.boot.context.properties.ConfigurationProperties进行分析 ConfigurationProperties 顶部注释 1 2 3 4 * @see ConfigurationPropertiesScan * @see ConstructorBinding * @see ConfigurationPropertiesBindingPostProcessor * @see EnableConfigurationProperties 看到ConfigurationPropertiesScan 去看</description>
    </item>
    <item>
      <title>SpringBoot-ConditionalOnBean</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringBoot/SpringBoot-ConditionalOnBean/</link>
      <pubDate>Wed, 06 Mar 2024 13:30:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringBoot/SpringBoot-ConditionalOnBean/</guid>
      <description>SpringBoot ConditionalOnBean Author: HuiFer 源码阅读仓库: SourceHot-spring-boot 在 SpringBoot 中有下列当 XXX 存在或不存的时候执行初始化 ConditionalOnBean ConditionalOnClass ConditionalOnCloudPlatform ConditionalOnExpression ConditionalOnJava ConditionalOnJndi ConditionalOnMissingBean ConditionalOnMissingClass ConditionalOnNotWebApplication ConditionalOnProperty ConditionalOnResource ConditionalOnSingleCandidate ConditionalOnWebApplication ConditionalOnBean 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(OnBeanCondition.class) public @interface ConditionalOnBean { /** * 需要匹配的 bean 类型 */ Class&amp;lt;?&amp;gt;[] value() default {}; /** * 需要匹配的 bean 类型 */ String[] type() default {}; /** * 匹配的 bean 注解 */ Class&amp;lt;? extends Annotation&amp;gt;[] annotation() default {}; /**</description>
    </item>
    <item>
      <title>Spring-Boot-Run</title>
      <link>https://index.zshipu.com/geek/post/code/docs/SpringBoot/Spring-Boot-Run/</link>
      <pubDate>Wed, 06 Mar 2024 13:29:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/SpringBoot/Spring-Boot-Run/</guid>
      <description>SpringBoot 启动方法 Author: HuiFer 源码阅读仓库: SourceHot-spring-boot 入口 通常一个简单的 SpringBoot 基础项目我们会有如下代码 1 2 3 4 5 6 7 8 9 10 @SpringBootApplication @RestController @RequestMapping(&amp;#34;/&amp;#34;) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 值得关注的有SpringApplication.run以及注解@SpringBootApplication run 方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20</description>
    </item>
    <item>
      <title>Sentinel限流算法的实现</title>
      <link>https://index.zshipu.com/geek/post/code/docs/Sentinel/Sentinel%E9%99%90%E6%B5%81%E7%AE%97%E6%B3%95%E7%9A%84%E5%AE%9E%E7%8E%B0/</link>
      <pubDate>Wed, 06 Mar 2024 12:07:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/Sentinel/Sentinel%E9%99%90%E6%B5%81%E7%AE%97%E6%B3%95%E7%9A%84%E5%AE%9E%E7%8E%B0/</guid>
      <description>Sentinel 中漏桶算法的实现 Sentinel 中漏桶算法通过 RateLimiterController 来实现，在漏桶算法中，会记录上一个请求的到达时间，如果新到达的请求与上一次到达的请求之间的时间差小于限流配置所规定的最小时间，新到达的请求将会排队等待规定的最小间隔到达，或是直接失败。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30</description>
    </item>
    <item>
      <title>Sentinel时间窗口的实现</title>
      <link>https://index.zshipu.com/geek/post/code/docs/Sentinel/Sentinel%E6%97%B6%E9%97%B4%E7%AA%97%E5%8F%A3%E7%9A%84%E5%AE%9E%E7%8E%B0/</link>
      <pubDate>Wed, 06 Mar 2024 12:06:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/Sentinel/Sentinel%E6%97%B6%E9%97%B4%E7%AA%97%E5%8F%A3%E7%9A%84%E5%AE%9E%E7%8E%B0/</guid>
      <description>获取时间窗口的主要流程 在 Sentinel 中，主要是通过 LeapArray 类来实现滑动时间窗口的实现和选择。在 sentinel 的这个获取时间窗口并为时间窗口添加指标的过程中，主要的流程为： 根据当前时间选择当前时间应该定位当前时间应该属于的时间窗口 id。 根据时间窗口 id 获取时间窗口。这里可能会存在四种情况： 时间窗口还未建立，那么</description>
    </item>
    <item>
      <title>Sentinel底层LongAdder的计数实现</title>
      <link>https://index.zshipu.com/geek/post/code/docs/Sentinel/Sentinel%E5%BA%95%E5%B1%82LongAdder%E7%9A%84%E8%AE%A1%E6%95%B0%E5%AE%9E%E7%8E%B0/</link>
      <pubDate>Wed, 06 Mar 2024 12:05:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/Sentinel/Sentinel%E5%BA%95%E5%B1%82LongAdder%E7%9A%84%E8%AE%A1%E6%95%B0%E5%AE%9E%E7%8E%B0/</guid>
      <description>LongAdder 的原理 在 LongAdder 中，底层通过多个数值进行累加来得到最后的结果。当多个线程对同一个 LongAdder 进行更新的时候，将会对这一些列的集合进行动态更新，以避免多线程之间的资源竞争。当需要得到 LongAdder 的具体的值的时候，将会将一系列的值进行求和作为最后的结果。 在高并发的竞争下进行类似指标数据的收集的时候，Long</description>
    </item>
    <item>
      <title>redis-sds</title>
      <link>https://index.zshipu.com/geek/post/code/docs/Redis/redis-sds/</link>
      <pubDate>Wed, 06 Mar 2024 12:04:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/Redis/redis-sds/</guid>
      <description>深挖 Redis 6.0 源码——SDS SDS（Simple Dynamic Strings, 简单动态字符串）是 Redis 的一种基本数据结构，主要是用于存储字符串和整数。 这篇文章里，我们就来探讨一下 Redis SDS 这种数据结构的底层实现原理。 学习之前，首先我们要明确，Redis 是一个使用 C 语言编写的键值对存储系统。 前置思考 我们首先考虑一个问题，如</description>
    </item>
    <item>
      <title>Redis</title>
      <link>https://index.zshipu.com/geek/post/code/docs/Redis/Redis/</link>
      <pubDate>Wed, 06 Mar 2024 12:03:00 +0000</pubDate>
      <guid>https://index.zshipu.com/geek/post/code/docs/Redis/Redis/</guid>
      <description>Redis Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库，并提供多种语言的 API。在这篇博客中，我们将介绍 Redis 的基本使用和常见操作。 1. 环境准备 首先，我们需要在本地安装 Redis。可以从官网下载对应版本的 Redis，这里我们使用的是 6.2.6 版本。下</description>
    </item>
  </channel>
</rss>
