io.druid.java.util.common 包
1 阅读io.druid.java.util.common.collect
package
知识点:
- Util类所提供的方法,通常都是public static xxxx
- 对于每一个传入的参数,都要做检查,具体使用com.google.common.base.Preconditions来检查,并且Preconditions的所有方法会在检查失败时候抛出RuntimeException,这也是为什么这几个方法并没有显示的throw
- @Nullable 注释的使用,合一很大程度上帮助IDE来识别问题代码,提高可读性。
2 阅读package io.druid.java.util.common.concurrent
- 这个package主要是提供了一些线程执行的工具类:线程执行类(定时执行,阻塞单线程执行),线程池,线程工厂类,线程执行配置类,本质上都是对java.util.concurrent.ExecutorService,java.util.concurrent.Executor,java.util.concurrent.ScheduledExecutorService的一层简单封装。 如果对这些类库的用法不熟悉,可以参看:Java Concurrency in Practice
- 单独提一下, io.druid.concurrent.ConcurrentAwaitableCounter 这个类提供了这样的功能:多线程环境下可以安全的进行自增increment(),同时还可以一直等待直到count达到了某个值。内部实现的机制是:内部有一个Sync类继承了AbstractQueuedLongSynchronizer。如此,多个线程就可以在队列中等待,直到内部的count计数到达了某个指定的值。
3 阅读package io.druid.java.util.common.config
- 该package只包含了俩类,Druid内部使用了org.skife.config的开源代码,难道Guice自带的配置参数读取功能不太好用?
/**
4 阅读package io.druid.java.util.common.granularity
- 该package包含了和Druid Query中granularity相关的代码,granularity的使用看这里。
- GranularityType是一个枚举类,主要列举了支持的格式
- Granularity是一个抽象类,具体会被NoneGranularity, AllGranularity, DurationGranularity, PeriodGranularity及各类继承。这些类都用了Jackson库来反序列化json string到具体的POJO。这几个类主要会被Druid具体的QueryBuilder等用到。主要就是把json string转换到具体的POJO。
5 package io.druid.java.util.common.jackson
- 只包含一个JacksonUtils类,并且只有两个TYPE_REFERENCE_MAP_STRING_OBJECT和TYPE_REFERENCE_MAP_STRING_STRING静态常量。
- Jackson中的TypeReference主要是用于记录泛型参数的类型信息(由于java中的类型擦除),这样就可以正确的反序列化。
6 package io.druid.java.util.common.guava
- 这个包中主要需要了解3个接口:Accumulator, Yielder, Sequence。其余的类都是这个三个接口的具体实现。这3个接口的设计非常优雅。
public
-
- Sequence代表可遍历的序列。如果是一般的场景,可以使用List,Array之类的,也可以遍历元素。稍微高级一点的用法是使用Iterator,这样遍历这个行为和底层具体如何存放数据就可以解耦,但是其缺点就是向外泄漏了数据元素。Sequence设计的目的就是要避免这个数据元素(资源,比如说每个元素是一个File)的泄漏。可以使用Accumulator来定义如何操作数据。简单地说,如果要遍历Sequence里的元素,不能使用for循环,而是提供需要一个Accumulator来操作。这样的好处是允许Sequence可以自己在内部调用Accumulator,并且更方便自己管理资源,而不是依赖调用者。
- Yielder代表一个‘生成器’的抽象。其作用非常类似于其他语言中的yield函数调用,可以把它简单的理解为一个链表,get返回头部的元素。初步的理解是,当Sequence调用toYielder时,返回的Yielder类自己内部已经存储好了计算的结果。
- Sequence接口的实现有FilteringSequence,LimitedSequence等,都使用了组合,而不是继承来复用代码,非常漂亮。
7 package io.druid.java.util.common.io
- 包含了主要用于存写smoosh文件的类,这些类主要会在创建Druid索引文件时用到:
- FileSmoosher 主要是把多个文件连接起来‘切分’成多个块,每个字节块的大小为maxChunkSize(可以提前配置)
- SmooshedFileMapper 把smoosh二进制文件映射到ByteBuffer中
8 package io.druid.java.util.common.lifecycle:就只有一个类Lifecycle,用于主动的管理对象的生命周期(这里的对象资源管理和JVM中的对象管理不是一个概念,这里的Lifecycle主要用处是在资源用完后,需要自动的调用close,来及时的清理和释放资源,这里的‘资源’可以是一个runnable,一个http client,一个file等,这些资源都需要在结束时及时的cleanup),主要是注册handler,在对象开始和结束的时候调用handler的方法。
9 package io.druid.java.util.common.logger:就只有一个Logger类,是对slf4j的封装,提供便携的方法:trace,debug等
10 package io.druid.java.util.common.parsers: CSV parser, JSON parser 主要就是解析json,csv文件
剩下的零零散散的数十个类基本都是Joda库的封装类,以及一些自定义的Exception类。common包的阅读至此结束。
io.druid.java.util.emitter 包
共有3个大的子package:core,factory,service以及一个EmittingLogger类。Emitter发射器,主要的功能就是把一个Event发送出去,至于发送到哪里,完全取决于实现,可以是通过http发射,可以是向日志发射,也可以是向特定的队列发射event。Emitter类在Druid中有很多不同的实现,主要是在StatsD,Kafka,Coordinator中被使用,用来发送特定event向目的地。你可以理解为是‘消费者-生产者’中‘生产者’的一个抽象。
- core:需要知道的是两大接口
public
实现了该接口的类有:HttpPostEmitter,LoggingEmitter,NoopEmitter,ParameterizedUriEmitter,从这些类的名字中就基本可以断定其Emitter背后实现的机制。还有一个ComposingEmitter类,可以传入一连串的Emitter,依次调用每个emitter,实现了功能的组合,这样的组合方式应用的很广泛。剩下的类基本就都是针对每个特定的Emitter的配置config类:HttpEmitterConfig等等。
- factory:工厂类,提供了一个总的接口工厂EmitterFactory,用于创建各种Emitter(由于Emitter类及其实现,主要被用在druid extension扩展包中,所以这个接口工厂EmitterFactory是用jackson来注释的,可以动态的创建),现提供了4中Emitter的子工厂类
- HttpEmitterFactory
- NoopEmitterFactory
- LoggingEmitterFactory
- ParametrizedUriEmitterFactory
@JsonTypeInfo
- service:该包中最重要的是ServiceEvent,ServiceEmitter
public
基本上是对一个service提供了一个专门的Emitter和event类型,其ServiceEvent加上了服务名和host名。在Druid Coordinator,Kafka Supervisor等服务中,都有用到。
package io.druid.java.util.http 包
该包定义了一个异步http客户端接口HttpClient,提供了一个默认的基本实现AbstractHttpClient类,其他的实现:CredentialedHttpClient,EnforceSslHttpClient,NettyHttpClient都是继承AbstractHttpClient类。
public
- 该接口定义返回的是一个ListenableFuture,是guava库中的接口,理由是该接口提供了比java原生库Future更好的功能,更加安全方便,具体的解释:看这里。
- 其余的类基本就是辅助类:Request,Response类是对http请求和回复的抽象,自身也提供一些方便的方法来解析header,status等
package io.druid.java.util.metrics 包
定义了一个Monitor接口,用来监控各个服务的指标,并在一定条件下,把这些监控的指标发射出去,以便于日志监控分析。在Druid其他的服务中,都有用到。
public
该包中提供了很多Monitor的实现:JvmMonitor,JvmCpuMonitor,SysMonitor等等,这里我就不一一列举了。