HBase的連接代碼很簡單,如下:
try (Connection connection = ConnectionFactory.createConnection(conf))
這裏用到了工廠模式進行Connection實例的創建,需要傳入的是配置參數管理類Configuration,在創建中首先需要把用戶信息添加進去: if (user == null) {
UserProvider provider = UserProvider.instantiate(conf);
user = provider.getCurrent();
}
return createConnection(conf, false, pool, user);
String className = conf.get(HConnection.HBASE_CLIENT_CONNECTION_IMPL,
ConnectionManager.HConnectionImplementation.class.getName());
Class<?> clazz = null;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new IOException(e);
}
try {
// Default HCM#HCI is not accessible; make it so before invoking.
Constructor<?> constructor =
clazz.getDeclaredConstructor(Configuration.class,
boolean.class, ExecutorService.class, User.class);
constructor.setAccessible(true);
return (Connection) constructor.newInstance(conf, managed, pool, user);
這裏使用了反射技術進行類對象的構造,從代碼中我們看到實際是調用了HConncetionImplementation的構造函數,這些類之間的相互關係如下圖所示:
從途中可以看出,HConnectionImplementation是實際的Connction實現類,接下來我們去看看該類的實例化過程:
HConnectionImplementation(Configuration conf, boolean managed,
ExecutorService pool, User user) throws IOException {
this(conf);
this.user = user;
this.batchPool = pool;
this.managed = managed;
this.registry = setupRegistry();
retrieveClusterId();
this.rpcClient = RpcClientFactory.createClient(this.conf, this.clusterId);
this.rpcControllerFactory = RpcControllerFactory.instantiate(conf);
// Do we publish the status?
boolean shouldListen = conf.getBoolean(HConstants.STATUS_PUBLISHED,
HConstants.STATUS_PUBLISHED_DEFAULT);
Class<? extends ClusterStatusListener.Listener> listenerClass =
conf.getClass(ClusterStatusListener.STATUS_LISTENER_CLASS,
ClusterStatusListener.DEFAULT_STATUS_LISTENER_CLASS,
ClusterStatusListener.Listener.class);
if (shouldListen) {
if (listenerClass == null) {
LOG.warn(HConstants.STATUS_PUBLISHED + " is true, but " +
ClusterStatusListener.STATUS_LISTENER_CLASS + " is not set - not listening status");
} else {
clusterStatusListener = new ClusterStatusListener(
new ClusterStatusListener.DeadServerHandler() {
@Override
public void newDead(ServerName sn) {
clearCaches(sn);
rpcClient.cancelConnections(sn);
}
}, conf, listenerClass);
}
}
}
好吧這看起來有點小複雜,它首先調用了另一個構造類
protected HConnectionImplementation(Configuration conf) {
this.conf = conf;
this.tableConfig = new TableConfiguration(conf);
this.closed = false;
this.pause = conf.getLong(HConstants.HBASE_CLIENT_PAUSE,
HConstants.DEFAULT_HBASE_CLIENT_PAUSE);
this.numTries = tableConfig.getRetriesNumber();
this.rpcTimeout = conf.getInt(
HConstants.HBASE_RPC_TIMEOUT_KEY,
HConstants.DEFAULT_HBASE_RPC_TIMEOUT);
if (conf.getBoolean(CLIENT_NONCES_ENABLED_KEY, true)) {
synchronized (nonceGeneratorCreateLock) {
if (ConnectionManager.nonceGenerator == null) {
ConnectionManager.nonceGenerator = new PerClientRandomNonceGenerator();
}
this.nonceGenerator = ConnectionManager.nonceGenerator;
}
} else {
this.nonceGenerator = new NoNonceGenerator();
}
stats = ServerStatisticTracker.create(conf);
this.asyncProcess = createAsyncProcess(this.conf);
this.interceptor = (new RetryingCallerInterceptorFactory(conf)).build();
this.rpcCallerFactory = RpcRetryingCallerFactory.instantiate(conf, interceptor, this.stats);
this.backoffPolicy = ClientBackoffPolicyFactory.create(conf);
}
ConnectionManager.nonceGenerator = new PerClientRandomNonceGenerator();//每個客戶端隨機的NonceGEnerator,主要是爲了生成clientidstats = ServerStatisticTracker.create(conf);創建跟蹤該connection所相關的region 信息監控實例
this.asyncProcess = createAsyncProcess(this.conf);創建一個同步進程實例,該進程主要負責持續的請求流
this.interceptor = (new RetryingCallerInterceptorFactory(conf)).build();//遠程服務器出現故障時,進行處理的機制
this.rpcCallerFactory = RpcRetryingCallerFactory.instantiate(conf, interceptor, this.stats);//RpcRetryingCaller創建工廠
this.backoffPolicy = ClientBackoffPolicyFactory.create(conf);//這個實際沒有具體的的類實現
同樣的我們也就只是分析一些關鍵步驟:
this.registry = setupRegistry();//用於獲取集羣的基本信息例如clusterid以及region location的meta數據
this.rpcClient = RpcClientFactory.createClient(this.conf, this.clusterId); //負責IPC調用相關
this.rpcControllerFactory = RpcControllerFactory.instantiate(conf);//
至此客戶端的啓動結束了,這裏其實主要是啓動兩個服務,
一個是用於request處理的AsyncProcess
一個是用於獲取服務器信息的Registry
還有就是負責RPC調用的RpcClient,相關主要類圖如下: