自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

程序员小潘

专注于Java后端技术分享!

  • 博客(327)
  • 资源 (1)
  • 收藏
  • 关注

原创 Elasticsearch快速上手

索引是文档的容器,就像关系数据库中,要存储行记录必须先创建数据库和表一样。ES6 及之前的版本还存在”类型“的概念,一个索引下可以存储多个类型的文档,但是不同类型下的文档却不是相互独立的,这些文档同属于一个 Lucene 索引,仅通过_type字段做逻辑区分,导致不同类型下的相同字段名无法实现不同的数据类型而出现问题,于是 ES7 废弃了类型的概念,ES8 彻底移除了类型。文档是可以被索引的最小信息单元,相当于关系数据库中的行记录。文档由若干个字段(Field)组成,每个字段是一个键值对。

2024-04-07 18:18:01 1074

原创 Spring事件监听机制

Spring 的事件监听机制,采用了观察者的设计模式。一套完整的事件监听流程是这样的,首先定义事件类,即ApplicationEvent的子类,它包含事件发生的时间戳timestamp和产生事件的来源source,以及自定义的其它事件属性;然后实现事件监听器 ApplicationListener 并注册到容器,订阅感兴趣的事件,Spring 会在事件发生时触发监听器;最后通过事件发布器 ApplicationEventPublisher 发布自定义事件。

2024-03-04 19:41:11 1059 1

原创 基于Redis商品库存扣减方案

电商业务场景下,对于库存的处理是比较重要的,表面上看只是对商品库存数做一个扣减操作,但是要做到不超卖、不少卖,同时还要保证高性能,却是一件非常困难的事。

2024-02-22 17:10:23 748

原创 Spring Bean的生命周期

Spring Bean 是 Spring IOC 容器负责实例化、组装和管理的对象,它和普通的 Java 对象并没有什么区别,唯一的区别就是它不是由开发人员自己 new 出来的,而是由容器负责创建的。IOC 容器除了实例化对象,还会负责管理对象之间的依赖关系,自动注入依赖和属性,甚至创建代理对象来对原始对象进行增强。生命周期是一个对象从创建到被销毁经历的整个过程,普通Java对象的生命周期是JVM分配内存,调用构造函数实例化对象,当该对象没有被引用后再由GC负责销毁并释放内存。

2024-02-18 20:33:50 919

原创 Redis分布式可重入锁实现方案

在单进程环境下,要保证一个代码块的同步执行,直接用关键字或即可。在分布式环境下,要保证多个节点的线程对代码块的同步访问,就必须要用到分布式锁方案。分布式锁实现方案有很多,有基于关系型数据库行锁实现的;有基于ZooKeeper临时顺序节点实现的;还有基于 Redis setnx 命令实现的。本文介绍一下基于 Redis 实现的分布式锁方案。

2024-02-18 15:03:32 1579

原创 ThreadLocalMap为什么用线性探测解决哈希冲突

ThreadLocal 本身不存储值,访问的是当前线程 ThreadLocalMap 里存储的数据副本,实现了线程间的数据隔离。只有当前线程能访问,也就不存在并发访问时的安全问题了。ThreadLocal 的核心是 ThreadLocalMap,它和 HashMap 不同的是:面对哈希冲突时,后者用的是链表法,而前者用的是线性探测法,为什么呢???

2024-01-19 11:33:26 507 1

原创 自定义Dubbo RPC通信协议

然后是定义grpc的 Service 和消息格式DispatcherService.proto 请求分发服务的定义RequestData.proto 请求消息的定义,主要是对 Invocation 的描述ResponseData.proto 响应消息的定义,主要是对 AppResponse 的描述使用插件把 proto 文件生成对应的 Java 类。

2024-01-18 08:42:07 1110

原创 Dubbo分层设计之Protocol层

Dubbo 框架采用分层设计,自上而下共分为十层。最底下的 Serialize 层关心的是如何序列化对象、往上的 Transporte 层关心的是如何把数据传输到远程、再往上的 Exchange 层关心的则是如何实现 请求-应答 消息交换模式、再往上就是 Protocol 层,它关心的是如何封装 RPC 调用,屏蔽底层细节。

2024-01-18 08:41:16 934

原创 Dubbo分层设计之Exchange层

Dubbo Exchanger 也可以基于 SPI 一键替换,我们实现一个自定义的 Exchanger,加深理解。首先,我们新建一个模块,并引入依赖:

2024-01-17 19:44:42 912

原创 基于JavaSocket重写Dubbo网络传输层

新建一个模块用来封装我们自己的传输层实现。因为要写的是 Dubbo 传输层的一个实现策略,所以要依赖

2024-01-17 19:44:03 982

原创 Dubbo分层设计之Transport层

Dubbo 框架采用分层设计,最底下的 Serialize 层负责把对象序列化为字节序列,再经过 Transport 层网络传输到对端。一次 RPC 调用,在 Dubbo 看来其实就是一段请求报文和一段响应报文的传输过程。

2024-01-15 11:14:26 1012

原创 Dubbo分层设计之Serialize层

Serialization 被设计成 SPI 接口,所以它可以很轻松的被替换。接下来,我们就基于 Fastjson2 写一个序列化模块,替换掉默认的 hessian2,让你对整个序列化过程理解的更加清楚。首先,我们新建一个模块。因为我们要依赖 Dubbo 提供的接口去实现一套新的序列化组件,所以自然要引入模块。又因为我们是基于 fastjson2 实现的,所以也得引入 fastjson2 的依赖。

2024-01-15 11:12:22 959

原创 Spring Boot Starter设计实现

Starter 是 Spring Boot 非常重要的一个硬核功能。通过 Starter 我们可以快速的引入一个功能或模块,而无须关心模块依赖的其它组件。关于配置,Spring Boot 采用“约定大于配置”的设计理念,Starter 一般都会提供默认配置,只有当我们有特殊需求的时候,才需要在里进行单独配置以覆盖掉默认配置。例如,我们开发一个 Web 应用,需要用到 Spring MVC、Tomcat 等组件,我们只需要依赖。

2024-01-11 16:52:27 635

原创 Spring Boot自动装配

跟自动装配相对立的就是手动装配,早期我们通过 xml 手动往容器里注册 bean 的方式就是手动装配。

2024-01-11 16:51:50 518

原创 SpringBoot内嵌Tomcat启动流程

Spring MVC 让开发者不用了解 Servlet 细节,专注于 Controller 编写 API 接口。Spring Boot 更是采用约定大于配置的设计思想,通过内嵌 Tomcat 的方式让开发者可以快速构建并部署一个 Web 应用。怎么做到的呢?

2024-01-11 16:51:12 562

原创 Spring循环引用和三级缓存

Spring 解决 Bean 之间的循环引用关系用到了三级缓存,那么问题来了。三级缓存是怎么用的?每一层的作用是什么?非得用三级吗?两级缓存行不行?

2024-01-09 20:13:04 1050

原创 Spring MVC接口数据加密传输

假设现在有个需求,要实现接口请求体参数和响应数据的加密传输,换作是你会如何实现呢?这个方案的缺点是代码侵入性太强,接口方法更应该专注于业务。另外就是处理起来太麻烦,会产生很多冗余代码。有没有更优雅的处理方式呢?

2024-01-04 09:18:14 1161

原创 Spring mvc WebDataBinder数据绑定器

DataBinder 是数据绑定器,它的作用是把一组属性值绑定到目标对象上,参数绑定的方式一般是通过 Java 反射。WebDataBinder 顾名思义,它是专门在 Web 环境使用的数据绑定器。“数据绑定”对于框架而言是一项基础能力,很多地方都有数据绑定的需求。以 Spring MVC 为例,框架需要把 HttpServletRequest 参数绑定到 Java 对象上。

2024-01-04 09:17:39 1275

原创 HandlerMethodArgumentResolver参数解析

被注解的方法就是一个请求处理器 handler,Spring MVC 会把该方法封装成 HandlerMethod 对象。HTTP 请求经过 RequestMappingInfo 条件匹配后最终路由到目标 HandlerMethod,接下来就是对目标方法的调用了。调用方法你得有参数吧,所以 Spring MVC 会先依赖 HandlerMethodArgumentResolverComposite 组件解析参数列表,再反射调用目标方法,本文重点参数的解析。

2024-01-04 09:17:05 879

原创 RequestMappingHandlerAdapter处理流程

DispatcherServlet 通过 HandlerMapping 匹配完各种条件后,终于找到目标处理器 handler了。但是 handler 是个 Object,它可能是 Spring MVC 内置的 handler,也可能是你自定义的 handler,总之 DispatcherServlet 并不认识它,没法指挥它干活。这个时候,就需要依赖 HandlerAdapter 组件了。它是处理器适配器,顾名思义它是协调 handler 干活的角色,它肯定认识它能指挥的 handler。

2024-01-04 09:16:25 907

原创 Spring MVC RequestMappingInfo路由条件匹配

我们已经知道,被标注的方法会被解析为 HandlerMethod,它也是 Spring MVC 中最常用的 Handler 类型。现在的问题是,HTTP 请求是如何路由到对应的 HandlerMethod?你可能脱口而出:根据请求的 Url 匹配啊!的确,Url 匹配是最简单一种规则,但事实上 Spring MVC 的功能之丰富超乎你想象。除此之外,你还可以根据请求方法、请求头、Content-Type、Accept、甚至自定义更复杂的路由规则。

2024-01-04 09:15:49 1318

原创 HandlerMapping处理器的查找过程

AbstractHandlerMapping 也采用了模板方法模式,它是其它实现类的基类,实现了一些通用逻辑。调用子类查找处理器没有找到尝试用默认处理器如果 handler 是字符串类型,则通过容器查找对应的 Bean 作为 handler获取能匹配到的 HandlerInterceptor,构建 HandlerExecutionChain// 查找Handler,交给子类// 如果是字符串,从容器查找bean作为handlerif (!

2024-01-04 09:14:21 848

原创 DispatcherServlet请求处理流程

DispatcherServlet 是 Spring MVC 的核心类,它本质是一个 Servlet,负责接管 HTTP 请求并把它分发给对应的处理器处理,最后处理响应结果渲染页面。DispatcherServlet 本身并不复杂,它提供了一个模板方法来处理请求,把请求处理的细节交给了依赖的其它组件。本文先分析 DispatcherServlet 的初始化流程,再分析请求的整体处理流程,至于请求处理中涉及到的其它组件,会另起篇幅。

2024-01-04 09:13:43 1056

原创 Spring MVC自定义请求处理器

为了让大家更好的理解 Spring MVC 处理 HTTP 请求的大致流程、以及这些组件的作用,我们自定义一个处理器来处理 HTTP 请求。前面说过了,在 Spring MVC 中 Handler 可以以任何形式存在,它可以是一个类,也可以是一个方法。逻辑很简单,输出一个超级简单的 HTML。光有 MyHandler 还不够,Spring MVC 又不认识它,没法指挥它干活啊。@Component// 是否支持给定的handler@Override。

2024-01-04 09:13:00 585

原创 Spring MVC之Handler的四种类型

在Spring MVC的架构里面,负责处理HTTP请求的组件叫Handler。DispatcherServlet会根据请求的URL查找对应的处理器Handler,再根据Handler查找对应的适配器,再通过协调Handler处理请求。Spring MVC并没有限制Handler的类型,使用Object来表示,Handler可以以任何形式存在。正因为如此,所以需要适配器来协调Handler工作。Spring MVC默认有四种类型的Handler,对应的也就有四种适配器。

2024-01-04 09:12:28 605

原创 Spring MVC之HandlerAdapter

ControllerServlet开发者还可以自定义Handler,面对各种各样类型的Handler,Spring MVC再也不能简单直接的面向接口编程了。于是Spring MVC采用了适配器模式,通过不同的适配器去协调不同的Handler工作,适配器本身是很容易抽象成接口的,所以Spring MVC又可以愉快的面向接口编程了。

2024-01-04 09:11:12 749

原创 Spring MVC之HandlerMapping

Spring MVC将请求处理器定义为handler,因为handler可以以很多形式存在,所以Spring并没有限制handler的类型,用Object来表示。然后又因为这个原因,Spring MVC针对不同的handler设计了不同的HandlerAdapter来协调handler处理请求。那么,Spring是怎么根据请求Request查找到对应的处理器handler的呢?

2024-01-04 09:10:35 1276

原创 RocketMQ5.0顺序消息设计实现

顺序消息是 RocketMQ 提供的一种高级消息类型,支持消费者按照发送消息的先后顺序获取消息,从而实现业务场景中的顺序处理。顺序消息的顺序关系通过消息组(MessageGroup)判定和识别,发送顺序消息时需要为每条消息设置归属的消息组,相同消息组的多条消息之间遵循先进先出的顺序关系,不同消息组、无消息组的消息之间不涉及顺序性。比如:一条订单从创建到完结整个生命周期内产生的消息,如果要保证消费的顺序性,则可以用订单号作为 MessageGroup。

2024-01-03 19:03:04 871

原创 RocketMQ5.0消息过滤

消费者订阅了某个主题后,RocketMQ 会将该主题中的所有消息投递给消费者。若消费者只需要关注部分消息,可通过设置过滤条件在 Broker 端进行过滤,只获取到需要关注的消息子集,避免接收到大量无效的消息。以电商交易场景为例,用户从下单到拿到商品,中间会产生很多消息,被不同的下游系统订阅消费。下游系统往往只关心自己需要处理的消息,比如支付系统只关心支付消息,这时候生产者就可以在发送消息的时候给消息打上标签,下游系统按需订阅即可。

2024-01-03 19:02:17 579

原创 RocketMQ5.0Pop消费模式

RocketMQ 5.0 消费者引入了一种新的消费模式:Pop 消费模式,目的是解决 Push 消费模式的一些痛点。要实现这个目标还是有不小的挑战,看看 RocketMQ 是如何做到的吧。

2024-01-03 19:01:42 1011

原创 RocketMQ5.0延时消息时间轮算法

RocketMQ 相较于其它消息队列产品的一个特性是支持延时消息,也就是说消息发送到 Broker 不会立马投递给消费者,要等待一个指定的延迟时间再投递,适用场景例如:下单后多长时间没付款系统自动关闭订单。RocketMQ 4.x 版本的延时消息存在一定的局限性,实现原理是:Broker 内置了名称为的Topic,包含 18 个对应延时级别的队列,每个延时级别的时间是固定的。

2024-01-03 19:00:53 1562

原创 RocketMQ5.0消息发送流程

RocketMQ 5.0 引入了新的 Proxy 组件,为了便于多语言客户端 SDK 的开发维护,客户端的很多功能也都下沉到了 Proxy,客户端因此变得更加轻量化了,新版客户端源码简洁易懂。源码相较于 4.x 版本变化很大,本文分析 RocketMQ 5.0 Producer 客户端和 Proxy 的消息发送整体流程。服务端源码版本基于 5.0.0、客户端源码版本基于 java-5.0.4。

2024-01-03 19:00:06 1076

原创 RocketMQ5.0新组件Proxy

RocketMQ 4.x 版本之前,一套完整的 MQ 服务包含的组件有:Namesrv、Broker、Consumer、Producer。RocketMQ 5.0 版本之后,官方引入了一个新的组件:Proxy,它的作用是什么呢?

2024-01-03 18:59:13 661 1

原创 Redis主从复制流程

主从复制是 Redis 实现服务高可用的关键特性之一,主节点通过把写命令异步传播给从节点的方式来实现数据同步。同时,为了避免从库因为网络问题断开导致数据不一致,主库会开辟一块主从复制积压缓冲区 repl_backlog 缓存最近的写命令,待从库恢复连接后,可以直接走增量同步。为了避免缓冲区膨胀,repl_backlog 采用固定大小循环写的方式,一旦从库落后的太久,需要增量同步的日志被主库覆盖掉了,就不得不触发全量同步,因此建议线上可以适当调大缓冲区的大小。

2023-10-17 17:42:25 173 1

原创 Redis AOF持久化和ReWrite

Redis 的 RDB 持久化机制简单直接,把某一时刻的所有键值对以二进制的方式写入到磁盘,特点是恢复速度快,尤其适合数据备份、主从复制场景。但如果你的目的是要保证数据可靠性,RDB 就不太适合了,因为 RDB 持久化不宜频繁触发,如果 Redis 触发 RDB 后又有新的数据写入,且还没来得及触发下一次 RDB 就宕机了,中间的数据就会丢失。在这种场景下,我们就急需一种增量备份的方式,只记录上一次 RDB 到现在为止所有的变更记录就好了,相较于全量备份,增量备份的数据量就小得多了。

2023-10-17 17:41:47 481

原创 Redis RDB持久化

我们知道 Redis 之所以快,很大程度是因为它的数据直接放在内存里,而内存是易失性存储器,只有通电才存储数据,断电数据就会丢失。这个时候就要看你的应用场景了,如果你只是拿 Redis 做关系型数据库的缓存,来加速数据的访问效率,那么 Redis 数据即使丢了也不影响,可以重新从关系型数据库中重新加载一遍。但如果你直接拿 Redis 当做数据库来用,在上面存储业务数据,那么你就要重点关注下 Redis 的持久化机制了。

2023-10-17 17:41:11 289

原创 Redis LFU缓存淘汰算法

Redis 在 4.0 版本之前的缓存淘汰算法,只支持 random 和 lru。random 太简单粗暴了,可能把热点数据给淘汰掉,一般不会使用。lru 比 random 好一点,会优先淘汰最久没被访问的数据,但是它也有一个缺点,就是无法真正表示数据的冷热程度。如下示例,A 之前被频繁访问,B 在执行 LRU 淘汰前恰巧被访问了一次,记录了最新的时间戳。此时触发 LRU 淘汰算法,反而会把 A 给淘汰掉。但事实是,A 的热度明显比 B 高。

2023-10-17 17:40:21 305

原创 Redis LRU缓存淘汰算法

内存不是无限大的,当我们向 Redis 写入的数据量超过了最大内存限制,Redis 就会启用缓存淘汰策略。配置缓存淘汰策略是有必要的,在使用缓存数据库时,我们要重点关注的一个指标就是缓存命中率,如果数据只会被访问一次,那它的缓存是没有意义的。所以我们要尽可能的提高缓存数据库的性价比,也就是提高缓存命中率。提高缓存命中率最直接的方式,就是尽可能的保证缓存里的总是热数据,冷数据随着时间推移慢慢淘汰掉。所以我们需要一个缓存淘汰算法,那就是 LRU。

2023-10-17 17:39:27 306

原创 HyperLogLog算法

现在很多站点基本都有统计 PV 和 UV 的需求,PV 的统计很简单,在 Redis 里面维护一个计数器,页面每访问一次计数器就 +1,获取 PV 就是读取计数器的值。相比之下,UV 的统计就比较麻烦了,因为要对用户去重,UV 统计其实就是基数统计,最简单的做法就是记录下集合中所有不重复的元素。比如,你可以用 Set 来统计,Set 不会存储重复的元素,用户每次访问都把 UserID 写入 Set 集合,最终调用 SCARD 命令获取集合元素数量即可。

2023-10-17 17:38:52 290

原创 Redis数据结构之listpack

当数据量较小时,Redis 会优先考虑用 ziplist 来存储 hash、list、zset,这么做可以有效的节省内存空间,因为 ziplist 是一块连续的内存空间,它采用一种紧凑的方式来存储元素。但是它也有缺点,比如查找的时间复杂度高、内存分配的开销、连锁更新的风险等。

2023-10-17 17:36:13 384

HashMap.java

JDK7的HashMap源码阅读,几乎给每个方法和属性都加上了中文注释。 可以帮助大家更好的阅读源码,可能有理解不对的地方,望指正。

2019-12-27

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除