Java NIO 学习笔记
一、概述
在 Java IO 中,最为核心的一个概念是流(Stream),面向流的编程,一个流要么是输入流,要么是输出流,不可能同时既是输入流又是输出流。
在 Java NIO 中,我们是面向块(block)或是缓冲区(buffer)编程的。Buffer本身就是一块内存,数据的读写都是通过 Buffer 来实现的,还提供了对于数据的结构化访问方式,并且可以追踪到系统的读写过程。
NIO 的核心是由 Channel、Buffer、Selector 三部分组成。
1.1 Channel
你可以将 Channel 理解成 IO 中的 Stream,数据可以从 Channel 读到 Buffer 中,也可以从 Buffer 写到 Channel 中【对 channel 的读写操作,必须要通过 Buffer 来进行,不能直接从 Channel 读写数据】。
和 Stream 相比又有一些不同:
Stream 的读写是单向的,而 Channel 是双向的:既可以从 Channel 中读取数据,又可以写数据到 Channel
Channel 可以异步地读写
Channel 中的数据总是要先读 ...
Simple Binary Encoding
一、前言
在本篇文章中,一起来学习下 SBE(Simple Binary Encoding) 传输协议,它和 protobuf 一样,都是二进制的传输协议,比 protobuf 传输性能更高,其涉及灵感来源于 fast binary variant of FIX,最初的涉及目标就是为了应用于金融级的低延迟交易系统中。在开源软件 Aeron 中,也广泛的使用 SBE 作为数据的传输媒介。
二、设计原则
2.1 Copy-Free
网络和存储系统处理数据时通常需要对数据缓冲区进行编码和解码。Copy-Free 的原则是不使用任何中间缓冲区来编码和解码数据。如果使用了中间缓存区,会因为多次的复制数据产生性能损耗。
SBE 采用直接对底层缓冲区进行编码和解码的方式,这样带来的限制是不支持直接发送长度大于传输缓冲区的数据,对于这种情况,需要进行分段发送和数据重组。
2.2 Native Type Mapping
Copy-Free 模式通过将数据直接编码为底层缓冲区中的本地类型而得到性能提升。比如 64 位整数可以作为单个 x86_64 MOV 指令直接编码到底层缓冲区中。如果数据的字节 ...
Agrona 高性高性能数据结构
Agrona 是 real-logic 开发的一个 Java 工具包,它提供了许多高性能的数据结构和工具方法,主要包括:
Buffers - Thread safe direct and atomic buffers for working with on and off heap memory with memory ordering semantics.
Lists - Array backed lists of int/long primitives to avoid boxing.
Maps - Open addressing and linear probing with int/long primitive keys to object reference values.
Maps - Open addressing and linear probing with int/long primitive keys to int/long values.
Sets - Open addressing and linear probing for int/long primit ...
Mockito 源码分析(4)——Annotation
在本篇文章中,将主要对 Mockito 中 @Mock、@Spy、@InjectMocks 这三个主要注解进行源码分析。
我们知道,如果想要使用 Mockito,要么需要在测试类的 @Before,执行 org.mockito.MockitoAnnotations#initMocks,要么在测试类上添加 @RunWith(MockitoJUnitRunner.class) 注解。下面就让我们从 MockitoAnnotations#initMocks 方法看起吧。
MockitoAnnotations#initMocks
initMocks() 方法一共就两行代码:加载 AnnotationEngine,调用 process() 方法,传入的 testClass 为需要启用 Mockito 的测试类:
先来看下 AnnotationEngine 的获取逻辑:
当 GlobalConfiguration 实例化时,调用 createConfig() 方法,得到 IMockitoConfiguration 实现。只要没有进行额外配置,这里的实现是 DefaultMockitoCon ...
Mockito 源码分析(3)——When 与 Then 与 Verify
先问大家一个问题,下图中我使用框子标出的代码,你觉得是红色、绿色、蓝色,执行的顺序是怎样的呢?
:::details 看一眼答案
执行顺序:蓝色 > 绿色 > 红色,想错了的面壁吧。。。
:::
在开始本文之前,咱先根据前面的文章,明确一下已知条件:
使用 Mockito#mock 返回的对象,它所属的类是被 mock 类的 proxy 代理类。
对于该 proxy 类:
是被 mock 类的子类,并且实现了 MockAccess 接口
具有一个名为 mockitoInterceptor 的属性,其类型为 MockMethodInterceptor
类中所有的方法都被拦截了,拦截处理的类为 DispatcherDefaultingToRealMethod
如果以上条件你还有疑问,请先别急着往下看,复习下上篇文章,巩固下认知。
下文我将使用这个例子为例,来进行 when 和 then API 的源码分析。
When
Matcher
首先执行的方法是 Mockito.eq(1L),在 Mockito 的父类 ArgumentMatchers,为我们提供了一系 ...
Mockito 源码分析(2)——Mock 与 Spy
Mock
上来先丢一张时序图,后面在看源码的时候可以结合这张图,更容易理解。
为了方便调试,我没有使用注解的方式
无论你是使用 Mockito.mock() 还是 PowerMockito.mock(),其都会调用 MockitoCore.mock 方法(这里需要注意,MockitoCore 对象是 Static 属性,因此全局仅有一个)。
进入 MockitoCore#mock 方法后,它做了主要三件事,如下图所示:
对上一步传入的 MockSettings 进行一系列校验
构建出传入类的 proxy 实例
调用 mockingStarted 方法
createMock 方法中最核心的就是前两行代码。如下图所示:
这里首先创建了 MockHandler 对象,它本身是一个接口。通过追查 MockHandlerFactory#createMockHandler 方法可以得知,这里使用了委派模式,真正的核心逻辑是由 MockHandlerImpl 处理的。
接着来看第二行的 MockMaker,它也是一个接口,通过 Plugins.getMockMaker() 方式获 ...
Mockito 源码分析(1)——基础概念
前言
作为一个合格的开发工程师,写好 UT(Unit Test) 是必备的技能,目前市面上 UT 工具很多。我选用了使用最为广泛的 Mockito + Powermock 的组合,来分析它的源码,希望能为大家带来收获。
请注意,本系列不会为大家介绍基础用法。
系列开始之前,首先约定下版本:
123456789101112131415161718<dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <scope>test</scope> <version>2.0.9</version></dependency><dependency> <groupId>org.powermock</groupId> <artifactId>powermock-ap ...
Protobuf 与 JSON 的互相转换
一、前言
Protobuf 默认并没有提供跟 JSON 的互相转换方法,虽然 Protobuf 对象自身有 toString() 方法,但是并非是 JSON 格式,而是形如:
1234567891011121314age: 57name: "urooP"sex: MALEgrade { key: 1 value { score: 2.589357441994722 rank: 32 }}parent { relation: "father" tel: "3286647499263"}
本篇文章中,我将使用 protobuf-java-util 实现 Protobuf 对象的 JSON 序列化,使用 fastjson 实现反序列化,在文章最后,我编写了一个 fastjson 的转换器,来帮助大家更加优雅的实现 Protobuf 的序列化与反序列化。
二、序列化与反序列化
2.1 基础配置
首先需要引入 protobuf-java-util 依 ...
Spring SchedulingConfigurer 实现动态定时任务
一、前言
大家在日常工作中,一定使用过 Spring 的 @Scheduled 注解吧,通过该注解可以非常方便的帮助我们实现任务的定时执行。
但是该注解是不支持运行时动态修改执行间隔的,不知道你在业务中有没有这些需求和痛点:
在服务运行时能够动态修改定时任务的执行频率和执行开关,而无需重启服务和修改代码
能够基于配置,在不同环境/机器上,实现定时任务执行频率的差异化
这些都可以通过 Spring 的 SchedulingConfigurer 注解来实现。
这个注解其实大家并不陌生,如果有使用过 @Scheduled 的话,因为 @Scheduled 默认是单线程执行的,因此如果存在多个任务同时触发,可能触发阻塞。使用 SchedulingConfigurer 可以配置用于执行 @Scheduled 的线程池,来避免这个问题。
12345678@Configurationpublic class ScheduleConfig implements SchedulingConfigurer { @Override public void configureTas ...
Java 双亲委派机制
一、ClassLoader
在介绍双亲委派机制之前,必须先要了解类加载器 ClassLoader,当 .java 文件经过编译生成 .class 文件后,需要通过 ClassLoader 将其加载入 JVM 中。
Java 中包括以下四类 ClassLoader:
Bootstrap ClassLoader 启动类加载器【主要负责加载核心类库(java,lang.*)等】
Extension ClassLoader 扩展类加载器【主要负责加载 jre/lib/ext 目录下的扩展类库】
Application ClassLoader 应用程序类加载器【主要负责加载当前应用程序的类】
Custom ClassLoader 自定义类加载器
1.1 获取 ClassLoader
通过 java.lang.Class#getClassLoader 方法就能够知道加载某个类的具体 ClassLoader,如下面代码所示:
12345678910111213import sun.net.spi.nameservice.dns.DNSNameService;public class Clas ...