Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.ltsopensource.remoting.AbstractRemotingClient Maven / Gradle / Ivy
package com.github.ltsopensource.remoting;
import com.github.ltsopensource.core.domain.Pair;
import com.github.ltsopensource.core.factory.NamedThreadFactory;
import com.github.ltsopensource.core.logger.Logger;
import com.github.ltsopensource.core.logger.LoggerFactory;
import com.github.ltsopensource.remoting.common.RemotingHelper;
import com.github.ltsopensource.remoting.exception.*;
import com.github.ltsopensource.remoting.protocol.RemotingCommand;
import java.net.SocketAddress;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Remoting客户端实现
*/
public abstract class AbstractRemotingClient extends AbstractRemoting implements RemotingClient {
protected static final Logger LOGGER = LoggerFactory.getLogger(RemotingHelper.RemotingLogName);
private static final long LockTimeoutMillis = 3000;
protected final RemotingClientConfig remotingClientConfig;
private final Lock lockChannelTables = new ReentrantLock();
private final ConcurrentHashMap channelTables = new ConcurrentHashMap();
// 定时器
private final Timer timer = new Timer("ClientHouseKeepingService", true);
// 处理Callback应答器
private final ExecutorService publicExecutor;
public AbstractRemotingClient(final RemotingClientConfig remotingClientConfig,
final ChannelEventListener channelEventListener) {
super(remotingClientConfig.getClientOnewaySemaphoreValue(), remotingClientConfig
.getClientAsyncSemaphoreValue(), channelEventListener);
this.remotingClientConfig = remotingClientConfig;
int publicThreadNums = remotingClientConfig.getClientCallbackExecutorThreads();
if (publicThreadNums <= 0) {
publicThreadNums = 4;
}
this.publicExecutor = Executors.newFixedThreadPool(publicThreadNums, new NamedThreadFactory("RemotingClientPublicExecutor", true));
}
@Override
public void start() throws RemotingException {
clientStart();
// 每隔1秒扫描下异步调用超时情况
this.timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
AbstractRemotingClient.this.scanResponseTable();
} catch (Exception e) {
LOGGER.error("scanResponseTable exception", e);
}
}
}, 1000 * 3, 1000);
if (this.channelEventListener != null) {
this.remotingEventExecutor.start();
}
}
protected abstract void clientStart() throws RemotingException;
@Override
public void shutdown() {
try {
this.timer.cancel();
for (ChannelWrapper cw : this.channelTables.values()) {
this.closeChannel(null, cw.getChannel());
}
this.channelTables.clear();
if (this.remotingEventExecutor != null) {
this.remotingEventExecutor.shutdown();
}
clientShutdown();
} catch (Exception e) {
LOGGER.error("NettyRemotingClient shutdown exception, ", e);
}
if (this.publicExecutor != null) {
try {
this.publicExecutor.shutdown();
} catch (Exception e) {
LOGGER.error("NettyRemotingServer shutdown exception, ", e);
}
}
}
protected abstract void clientShutdown();
private Channel getAndCreateChannel(final String addr) throws InterruptedException {
ChannelWrapper cw = this.channelTables.get(addr);
if (cw != null && cw.isConnected()) {
return cw.getChannel();
}
return this.createChannel(addr);
}
private Channel createChannel(final String addr) throws InterruptedException {
ChannelWrapper cw = this.channelTables.get(addr);
if (cw != null && cw.isConnected()) {
return cw.getChannel();
}
// 进入临界区后,不能有阻塞操作,网络连接采用异步方式
if (this.lockChannelTables.tryLock(LockTimeoutMillis, TimeUnit.MILLISECONDS)) {
try {
boolean createNewConnection = false;
cw = this.channelTables.get(addr);
if (cw != null) {
// channel正常
if (cw.isConnected()) {
return cw.getChannel();
}
// 正在连接,退出锁等待
else if (!cw.getChannelFuture().isDone()) {
createNewConnection = false;
}
// 说明连接不成功
else {
this.channelTables.remove(addr);
createNewConnection = true;
}
}
// ChannelWrapper不存在
else {
createNewConnection = true;
}
if (createNewConnection) {
ChannelFuture channelFuture =
connect(RemotingHelper.string2SocketAddress(addr));
LOGGER.info("createChannel: begin to connect remote host[{}] asynchronously", addr);
cw = new ChannelWrapper(channelFuture);
this.channelTables.put(addr, cw);
}
} catch (Exception e) {
LOGGER.error("createChannel: create channel exception", e);
} finally {
this.lockChannelTables.unlock();
}
} else {
LOGGER.warn("createChannel: try to lock channel table, but timeout, {}ms", LockTimeoutMillis);
}
if (cw != null) {
ChannelFuture channelFuture = cw.getChannelFuture();
if (channelFuture.awaitUninterruptibly(this.remotingClientConfig.getConnectTimeoutMillis())) {
if (cw.isConnected()) {
LOGGER.info("createChannel: connect remote host[{}] success, {}", addr,
channelFuture.toString());
return cw.getChannel();
} else {
LOGGER.warn(
"createChannel: connect remote host[" + addr + "] failed, "
+ channelFuture.toString(), channelFuture.cause());
}
} else {
LOGGER.warn("createChannel: connect remote host[{}] timeout {}ms, {}", addr,
this.remotingClientConfig.getConnectTimeoutMillis(), channelFuture.toString());
}
}
return null;
}
protected abstract ChannelFuture connect(SocketAddress socketAddress);
public void closeChannel(final String addr, final Channel channel) {
if (null == channel)
return;
final String addrRemote = null == addr ? RemotingHelper.parseChannelRemoteAddr(channel) : addr;
try {
if (this.lockChannelTables.tryLock(LockTimeoutMillis, TimeUnit.MILLISECONDS)) {
try {
boolean removeItemFromTable = true;
final ChannelWrapper prevCW = this.channelTables.get(addrRemote);
LOGGER.info("closeChannel: begin close the channel[{}] Found: {}", addrRemote,
(prevCW != null));
if (null == prevCW) {
LOGGER.info(
"closeChannel: the channel[{}] has been removed from the channel table before",
addrRemote);
removeItemFromTable = false;
} else if (prevCW.getChannel() != channel) {
LOGGER.info(
"closeChannel: the channel[{}] has been closed before, and has been created again, nothing to do.",
addrRemote);
removeItemFromTable = false;
}
if (removeItemFromTable) {
this.channelTables.remove(addrRemote);
LOGGER.info("closeChannel: the channel[{}] was removed from channel table", addrRemote);
}
RemotingHelper.closeChannel(channel);
} catch (Exception e) {
LOGGER.error("closeChannel: close the channel exception", e);
} finally {
this.lockChannelTables.unlock();
}
} else {
LOGGER.warn("closeChannel: try to lock channel table, but timeout, {}ms", LockTimeoutMillis);
}
} catch (InterruptedException e) {
LOGGER.error("closeChannel exception", e);
}
}
public void closeChannel(final Channel channel) {
if (null == channel)
return;
try {
if (this.lockChannelTables.tryLock(LockTimeoutMillis, TimeUnit.MILLISECONDS)) {
try {
boolean removeItemFromTable = true;
ChannelWrapper prevCW = null;
String addrRemote = null;
for (String key : channelTables.keySet()) {
ChannelWrapper prev = this.channelTables.get(key);
if (prev.getChannel() != null) {
if (prev.getChannel() == channel) {
prevCW = prev;
addrRemote = key;
break;
}
}
}
if (null == prevCW) {
LOGGER.info(
"eventCloseChannel: the channel has been removed from the channel table before");
removeItemFromTable = false;
}
if (removeItemFromTable) {
this.channelTables.remove(addrRemote);
LOGGER.info("closeChannel: the channel[{}] was removed from channel table", addrRemote);
RemotingHelper.closeChannel(channel);
}
} catch (Exception e) {
LOGGER.error("closeChannel: close the channel exception", e);
} finally {
this.lockChannelTables.unlock();
}
} else {
LOGGER.warn("closeChannel: try to lock channel table, but timeout, {}ms", LockTimeoutMillis);
}
} catch (InterruptedException e) {
LOGGER.error("closeChannel exception", e);
}
}
@Override
public void registerProcessor(int requestCode, RemotingProcessor processor, ExecutorService executor) {
ExecutorService executorThis = executor;
if (null == executor) {
executorThis = this.publicExecutor;
}
Pair pair =
new Pair(processor, executorThis);
this.processorTable.put(requestCode, pair);
}
@Override
public void registerDefaultProcessor(RemotingProcessor processor, ExecutorService executor) {
this.defaultRequestProcessor = new Pair(processor, executor);
}
@Override
public RemotingCommand invokeSync(String addr, final RemotingCommand request, long timeoutMillis)
throws InterruptedException, RemotingConnectException, RemotingSendRequestException,
RemotingTimeoutException {
final Channel channel = this.getAndCreateChannel(addr);
if (channel != null && channel.isConnected()) {
try {
return this.invokeSyncImpl(channel, request, timeoutMillis);
} catch (RemotingSendRequestException e) {
LOGGER.warn("invokeSync: send request exception, so close the channel[{}]", addr);
this.closeChannel(addr, channel);
throw e;
} catch (RemotingTimeoutException e) {
LOGGER.warn("invokeSync: wait response timeout exception, the channel[{}]", addr);
// 超时异常如果关闭连接可能会产生连锁反应
// this.closeChannel(addr, channel);
throw e;
}
} else {
this.closeChannel(addr, channel);
throw new RemotingConnectException(addr);
}
}
@Override
public void invokeAsync(String addr, RemotingCommand request, long timeoutMillis,
AsyncCallback asyncCallback) throws InterruptedException, RemotingConnectException,
RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
final Channel channel = this.getAndCreateChannel(addr);
if (channel != null && channel.isConnected()) {
try {
this.invokeAsyncImpl(channel, request, timeoutMillis, asyncCallback);
} catch (RemotingSendRequestException e) {
LOGGER.warn("invokeAsync: send request exception, so close the channel[{}]", addr);
this.closeChannel(addr, channel);
throw e;
}
} else {
this.closeChannel(addr, channel);
throw new RemotingConnectException(addr);
}
}
@Override
public void invokeOneway(String addr, RemotingCommand request, long timeoutMillis)
throws InterruptedException, RemotingConnectException, RemotingTooMuchRequestException,
RemotingTimeoutException, RemotingSendRequestException {
final Channel channel = this.getAndCreateChannel(addr);
if (channel != null && channel.isConnected()) {
try {
this.invokeOnewayImpl(channel, request, timeoutMillis);
} catch (RemotingSendRequestException e) {
LOGGER.warn("invokeOneway: send request exception, so close the channel[{}]", addr);
this.closeChannel(addr, channel);
throw e;
}
} else {
this.closeChannel(addr, channel);
throw new RemotingConnectException(addr);
}
}
@Override
protected ExecutorService getCallbackExecutor() {
return this.publicExecutor;
}
private class ChannelWrapper {
private final ChannelFuture channelFuture;
public ChannelWrapper(ChannelFuture channelFuture) {
this.channelFuture = channelFuture;
}
public boolean isConnected() {
return channelFuture.isConnected();
}
private Channel getChannel() {
return channelFuture.getChannel();
}
private ChannelFuture getChannelFuture() {
return this.channelFuture;
}
}
}