阿里開源分佈式事務中間件fescar源碼分析
fescar架構及原理
fescar開源後,網絡上有不少講解其原理的文章,這裏就引入其中一篇,個人認爲也建的比較透徹。文章地址:
《阿里巴巴開源分佈式事務解決方案 Fescar》
這裏引入上面文章的部分圖片及內容, 架構及說明:
- Transaction Coordinator (TC): 事務協調器,維護全局事務的運行狀態,負責協調並驅動全局事務的提交或回滾。
- Transaction Manager ™: 控制全局事務的邊界,負責開啓一個全局事務,並最終發起全局提交或全局回滾的決議。
- Resource Manager (RM):
控制分支事務,負責分支註冊、狀態彙報,並接收事務協調器的指令,驅動分支(本地)事務的提交和回滾。
一個典型的分佈式事務過程:
- TM 向 TC 申請開啓一個全局事務,全局事務創建成功並生成一個全局唯一的 XID。
- XID 在微服務調用鏈路的上下文中傳播。
- RM 向 TC 註冊分支事務,將其納入 XID 對應全局事務的管轄。
- TM 向 TC 發起針對 XID 的全局提交或回滾決議。
- TC 調度 XID 下管轄的全部分支事務完成提交或回滾請求。
好,具體架構及過程可以詳細讀原文, 這裏對應架構組成,分析源碼。
三個系統,fescar server, 主事務的server, 子事務的server, 系統之間通過netty 完成rpc調用
主事務的server:
這裏的代碼實現跟本地的事務的事項非常匹配, 通過是 transaction來開啓事務,通過transactionManager真正實現事務的邏輯。而使用模板transactionTemplate方便事務的使用。
GlobalTransactiona註解來設置一個接口需要開啓分佈式事務, 通過AOP, 對註解方法做切面,切入事務代碼,加入事務處理。 GlobalTransactionalInterceptor 主要實現:
@Override
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
final GlobalTransactional anno = getAnnotation(methodInvocation.getMethod());
if (anno != null) {
try {
return transactionalTemplate.execute(new TransactionalExecutor() {
@Override
public Object execute() throws Throwable {
return methodInvocation.proceed();
}
@Override
public int timeout() {
return anno.timeoutMills();
}
@Override
public String name() {
if (anno.name() != null) {
return anno.name();
}
return formatMethod(methodInvocation.getMethod());
}
});
} catch (TransactionalExecutor.ExecutionException e) {
TransactionalExecutor.Code code = e.getCode();
switch (code) {
case RollbackDone:
throw e.getOriginalException();
case BeginFailure:
failureHandler.onBeginFailure(e.getTransaction(), e.getCause());
throw e.getCause();
case CommitFailure:
failureHandler.onCommitFailure(e.getTransaction(), e.getCause());
throw e.getCause();
case RollbackFailure:
failureHandler.onRollbackFailure(e.getTransaction(), e.getCause());
throw e.getCause();
default:
throw new ShouldNeverHappenException("Unknown TransactionalExecutor.Code: " + code);
}
}
}
return methodInvocation.proceed();
}
可以看到Interceptor主要通過template來加入事務, 而template的代碼:
// 1. get or create a transaction
GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
// 2. begin transaction
try {
tx.begin(business.timeout(), business.name());
} catch (TransactionException txe) {
throw new TransactionalExecutor.ExecutionException(tx, txe,
TransactionalExecutor.Code.BeginFailure);
}
Object rs = null;
try {
// Do Your Business
rs = business.execute();
} catch (Throwable ex) {
// 3. any business exception, rollback.
try {
tx.rollback();
// 3.1 Successfully rolled back
throw new TransactionalExecutor.ExecutionException(tx, TransactionalExecutor.Code.RollbackDone, ex);
} catch (TransactionException txe) {
// 3.2 Failed to rollback
throw new TransactionalExecutor.ExecutionException(tx, txe,
TransactionalExecutor.Code.RollbackFailure, ex);
}
}
// 4. everything is fine, commit.
try {
tx.commit();
} catch (TransactionException txe) {
// 4.1 Failed to commit
throw new TransactionalExecutor.ExecutionException(tx, txe,
TransactionalExecutor.Code.CommitFailure);
}
return rs;
}
TransactionalTemplate跟本地事務模板幾乎沒什麼區別, 而差別就是GlobalTransaction引用的TransactionManager上, 默認的實現 DefaultTransactionManager:
@Override
public String begin(String applicationId, String transactionServiceGroup, String name, int timeout) throws TransactionException {
GlobalBeginRequest request = new GlobalBeginRequest();
request.setTransactionName(name);
request.setTimeout(timeout);
GlobalBeginResponse response = (GlobalBeginResponse) syncCall(request);
return response.getXid();
}
@Override
public GlobalStatus commit(String xid) throws TransactionException {
long txId = XID.getTransactionId(xid);
GlobalCommitRequest globalCommit = new GlobalCommitRequest();
globalCommit.setTransactionId(txId);
GlobalCommitResponse response = (GlobalCommitResponse) syncCall(globalCommit);
return response.getGlobalStatus();
}
@Override
public GlobalStatus rollback(String xid) throws TransactionException {
long txId = XID.getTransactionId(xid);
GlobalRollbackRequest globalRollback = new GlobalRollbackRequest();
globalRollback.setTransactionId(txId);
GlobalRollbackResponse response = (GlobalRollbackResponse) syncCall(globalRollback);
return response.getGlobalStatus();
}
可以看到,所有實現都是一個rpc的請求, 而這個請求都是發送給fescar server。
fescar server
分佈事務協調的服務裏面,最主要就兩個類DefaultCoordinator, DefaultCore, 而Coordinator依賴Core來實現真正的業務邏輯, DefaultCoordinator處理來自主事務和子事務的協調處理。
@Override
public String begin(String applicationId, String transactionServiceGroup, String name, int timeout) throws TransactionException {
GlobalSession session = GlobalSession.createGlobalSession(
applicationId, transactionServiceGroup, name, timeout);
session.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
session.begin();
return XID.generateXID(session.getTransactionId());
}
@Override
protected void doGlobalBegin(GlobalBeginRequest request, GlobalBeginResponse response, RpcContext rpcContext) throws TransactionException {
response.setXid(core.begin(rpcContext.getApplicationId(), rpcContext.getTransactionServiceGroup(), request.getTransactionName(), request.getTimeout()));
}
@Override
protected void doGlobalCommit(GlobalCommitRequest request, GlobalCommitResponse response, RpcContext rpcContext) throws TransactionException {
response.setGlobalStatus(core.commit(XID.generateXID(request.getTransactionId())));
}
@Override
protected void doGlobalRollback(GlobalRollbackRequest request, GlobalRollbackResponse response, RpcContext rpcContext) throws TransactionException {
response.setGlobalStatus(core.rollback(XID.generateXID(request.getTransactionId())));
}
@Override
protected void doGlobalStatus(GlobalStatusRequest request, GlobalStatusResponse response, RpcContext rpcContext) throws TransactionException {
response.setGlobalStatus(core.getStatus(XID.generateXID(request.getTransactionId())));
}
@Override
protected void doBranchRegister(BranchRegisterRequest request, BranchRegisterResponse response, RpcContext rpcContext) throws TransactionException {
response.setTransactionId(request.getTransactionId());
response.setBranchId(core.branchRegister(request.getBranchType(), request.getResourceId(), rpcContext.getClientId(),
XID.generateXID(request.getTransactionId()), request.getLockKey()));
}
可以看到實現都依賴Core。 這裏再看DefaultCore的實現:
@Override
public GlobalStatus commit(String xid) throws TransactionException {
GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
if (globalSession == null) {
return GlobalStatus.Finished;
}
GlobalStatus status = globalSession.getStatus();
globalSession.closeAndClean(); // Highlight: Firstly, close the session, then no more branch can be registered.
if (status == GlobalStatus.Begin) {
if (globalSession.canBeCommittedAsync()) {
asyncCommit(globalSession);
} else {
doGlobalCommit(globalSession, false);
}
}
return globalSession.getStatus();
}
@Override
public void doGlobalCommit(GlobalSession globalSession, boolean retrying) throws TransactionException {
for (BranchSession branchSession : globalSession.getSortedBranches()) {
BranchStatus currentStatus = branchSession.getStatus();
if (currentStatus == BranchStatus.PhaseOne_Failed) {
continue;
}
try {
BranchStatus branchStatus = resourceManagerInbound.branchCommit(XID.generateXID(branchSession.getTransactionId()), branchSession.getBranchId(),
branchSession.getResourceId(), branchSession.getApplicationData());
switch (branchStatus) {
case PhaseTwo_Committed:
globalSession.removeBranch(branchSession);
continue;
case PhaseTwo_CommitFailed_Unretriable:
if (globalSession.canBeCommittedAsync()) {
LOGGER.error("By [" + branchStatus + "], failed to commit branch " + branchSession);
continue;
} else {
globalSession.changeStatus(GlobalStatus.CommitFailed);
globalSession.end();
LOGGER.error("Finally, failed to commit global[" + globalSession.getTransactionId() + "] since branch[" + branchSession.getBranchId() + "] commit failed");
return;
}
default:
if (!retrying) {
queueToRetryCommit(globalSession);
return;
}
if (globalSession.canBeCommittedAsync()) {
LOGGER.error("By [" + branchStatus + "], failed to commit branch " + branchSession);
continue;
} else {
LOGGER.error("Failed to commit global[" + globalSession.getTransactionId() + "] since branch[" + branchSession.getBranchId() + "] commit failed, will retry later.");
return;
}
}
} catch (Exception ex) {
LOGGER.info("Exception committing branch " + branchSession, ex);
if (!retrying) {
queueToRetryCommit(globalSession);
if (ex instanceof TransactionException) {
throw (TransactionException) ex;
} else {
throw new TransactionException(ex);
}
}
}
}
if (globalSession.hasBranch()) {
LOGGER.info("Global[" + globalSession.getTransactionId() + "] committing is NOT done.");
return;
}
globalSession.changeStatus(GlobalStatus.Committed);
globalSession.end();
LOGGER.info("Global[" + globalSession.getTransactionId() + "] committing is successfully done.");
}
@Override
public GlobalStatus rollback(String xid) throws TransactionException {
GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
if (globalSession == null) {
return GlobalStatus.Finished;
}
GlobalStatus status = globalSession.getStatus();
globalSession.close(); // Highlight: Firstly, close the session, then no more branch can be registered.
if (status == GlobalStatus.Begin) {
globalSession.changeStatus(GlobalStatus.Rollbacking);
doGlobalRollback(globalSession, false);
}
return globalSession.getStatus();
}
@Override
public void doGlobalRollback(GlobalSession globalSession, boolean retrying) throws TransactionException {
for (BranchSession branchSession : globalSession.getReverseSortedBranches()) {
BranchStatus currentBranchStatus = branchSession.getStatus();
if (currentBranchStatus == BranchStatus.PhaseOne_Failed) {
continue;
}
try {
BranchStatus branchStatus = resourceManagerInbound.branchRollback(XID.generateXID(branchSession.getTransactionId()), branchSession.getBranchId(),
branchSession.getResourceId(), branchSession.getApplicationData());
switch (branchStatus) {
case PhaseTwo_Rollbacked:
globalSession.removeBranch(branchSession);
LOGGER.error("Successfully rolled back branch " + branchSession);
continue;
case PhaseTwo_RollbackFailed_Unretriable:
GlobalStatus currentStatus = globalSession.getStatus();
if (currentStatus.name().startsWith("Timeout")) {
globalSession.changeStatus(GlobalStatus.TimeoutRollbackFailed);
} else {
globalSession.changeStatus(GlobalStatus.RollbackFailed);
}
globalSession.end();
LOGGER.error("Failed to rollback global[" + globalSession.getTransactionId() + "] since branch[" + branchSession.getBranchId() + "] rollback failed");
return;
default:
LOGGER.info("Failed to rollback branch " + branchSession);
if (!retrying) {
queueToRetryRollback(globalSession);
}
return;
}
} catch (Exception ex) {
LOGGER.info("Exception rollbacking branch " + branchSession, ex);
if (!retrying) {
queueToRetryRollback(globalSession);
if (ex instanceof TransactionException) {
throw (TransactionException) ex;
} else {
throw new TransactionException(ex);
}
}
}
}
GlobalStatus currentStatus = globalSession.getStatus();
if (currentStatus.name().startsWith("Timeout")) {
globalSession.changeStatus(GlobalStatus.TimeoutRollbacked);
} else {
globalSession.changeStatus(GlobalStatus.Rollbacked);
}
globalSession.end();
}
可以看到開啓一個事務,就是創建一個session,並返回xid, xid必須在分佈式調用中傳遞。
而commit和rollback都需要遍歷分支事務,通過netty的rpc messge通知子事務的提交或者回滾。
子事務的server
在fescar原理講解知道, fescar對XA的改進是,它的二段提交,子事務只有在第一段才鎖庫,只要是正常完成,第二段是不需要鎖庫,如果需要回滾,則根據記錄的undo log來做回退處理。
這樣基於DB做操作記錄來完成DB回退,只需要在業務失敗時候回退,減少鎖庫的時間,而比起實現正向和反向的冪等接口,這對開發來說更簡單。
因此重點看看子事務DataSource的代理類如何實現日記記錄,還有AbstractDMLBaseExecutor及UndoLogManager實現DB回滾,代碼邏輯:
DataSourceProxy, ConnectionProxy:DataSourceProxy只是通過ConnectionProxy實現日誌記錄, 重點看ConnectionProxy裏的實現邏輯
public void prepareUndoLog(SQLType sqlType, String tableName, TableRecords beforeImage, TableRecords afterImage) throws SQLException {
TableRecords lockKeyRecords = afterImage;
if (sqlType == SQLType.DELETE) {
lockKeyRecords = beforeImage;
}
String lockKeys = buildLockKey(lockKeyRecords);
context.appendLockKey(lockKeys);
SQLUndoLog sqlUndoLog = buildUndoItem(sqlType, tableName, beforeImage, afterImage);
context.appendUndoItem(sqlUndoLog);
}
看到ConnectionProxy的undo日誌只是被放入上下文,而在這之前undo日誌已經整理併入庫,這是在AbstractDMLBaseExecutor 實現:
protected T executeAutoCommitFalse(Object[] args) throws Throwable {
TableRecords beforeImage = beforeImage();
T result = statementCallback.execute(statementProxy.getTargetStatement(), args);
TableRecords afterImage = afterImage(beforeImage);
statementProxy.getConnectionProxy().prepareUndoLog(sqlRecognizer.getSQLType(), sqlRecognizer.getTableName(), beforeImage, afterImage);
return result;
}
protected T executeAutoCommitTrue(Object[] args) throws Throwable {
T result = null;
AbstractConnectionProxy connectionProxy = statementProxy.getConnectionProxy();
LockRetryController lockRetryController = new LockRetryController();
try {
connectionProxy.setAutoCommit(false);
while (true) {
try {
result = executeAutoCommitFalse(args);
connectionProxy.commit();
break;
} catch (LockConflictException lockConflict) {
lockRetryController.sleep(lockConflict);
}
}
} finally {
connectionProxy.setAutoCommit(true);
}
return result;
}
從executeAutoCommitFalse方法看到只是業務sql前先整理beforeImage,執行業務sql,在整理afterImage。而他是怎樣整理before和after的鏡像,居然可以看對應的實現類,這裏就不詳細貼上來了。
在正常情況提交不需要做額外的事情,本地事務已經提交了。 而如果回滾則找到undo日誌執行回滾。
DataSourceManager
@Override
public BranchStatus branchCommit(String xid, long branchId, String resourceId, String applicationData) throws TransactionException {
return asyncWorker.branchCommit(xid, branchId, resourceId, applicationData);
}
@Override
public BranchStatus branchRollback(String xid, long branchId, String resourceId, String applicationData) throws TransactionException {
DataSourceProxy dataSourceProxy = get(resourceId);
if (dataSourceProxy == null) {
throw new ShouldNeverHappenException();
}
try {
UndoLogManager.undo(dataSourceProxy, xid, branchId);
} catch (TransactionException te) {
if (te.getCode() == TransactionExceptionCode.BranchRollbackFailed_Unretriable) {
return BranchStatus.PhaseTwo_RollbackFailed_Unretriable;
} else {
return BranchStatus.PhaseTwo_RollbackFailed_Retriable;
}
}
return BranchStatus.PhaseTwo_Rollbacked;
}
UndoLogManager的undo實現:
public static void undo(DataSourceProxy dataSourceProxy, String xid, long branchId) throws TransactionException {
assertDbSupport(dataSourceProxy.getTargetDataSource().getDbType());
Connection conn = null;
ResultSet rs = null;
PreparedStatement selectPST = null;
try {
conn = dataSourceProxy.getPlainConnection();
// The entire undo process should run in a local transaction.
conn.setAutoCommit(false);
// Find UNDO LOG
selectPST = conn.prepareStatement(SELECT_UNDO_LOG_SQL);
selectPST.setLong(1, branchId);
selectPST.setString(2, xid);
rs = selectPST.executeQuery();
while (rs.next()) {
Blob b = rs.getBlob("rollback_info");
String rollbackInfo = StringUtils.blob2string(b);
BranchUndoLog branchUndoLog = UndoLogParserFactory.getInstance().decode(rollbackInfo);
for (SQLUndoLog sqlUndoLog : branchUndoLog.getSqlUndoLogs()) {
TableMeta tableMeta = TableMetaCache.getTableMeta(dataSourceProxy, sqlUndoLog.getTableName());
sqlUndoLog.setTableMeta(tableMeta);
AbstractUndoExecutor undoExecutor = UndoExecutorFactory.getUndoExecutor(dataSourceProxy.getDbType(), sqlUndoLog);
undoExecutor.executeOn(conn);
}
}
deleteUndoLog(xid, branchId, conn);
conn.commit();
} catch (Throwable e) {
if (conn != null) {
try {
conn.rollback();
} catch (SQLException rollbackEx) {
LOGGER.warn("Failed to close JDBC resource while undo ... ", rollbackEx);
}
}
throw new TransactionException(BranchRollbackFailed_Retriable, String.format("%s/%s", branchId, xid), e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (selectPST != null) {
selectPST.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException closeEx) {
LOGGER.warn("Failed to close JDBC resource while undo ... ", closeEx);
}
}
}
至此從全局事務到分支事務的begin,commit, rollback已經完成, 下面在看看其中涉及的一些公共部分,netty message rpc。
netty message rpc
雖然fescar是一套CS的request和response模式, 但也可以看做是一個基於message的rpc, 從rpc的幾個方面來解析源碼。 也可以從中瞭解rpc架構基本組成:
協議與網絡
這通過netty做網絡通信,基於socket, 而協議定義了一個rpcmessage,裏面分成header和body, 代碼如下:
public class RpcMessage {
private static AtomicLong NEXT_ID = new AtomicLong(0);
public static long getNextMessageId() {
return NEXT_ID.incrementAndGet();
}
private long id;
private boolean isAsync;
private boolean isRequest;
private boolean isHeartbeat;
private Object body;
而body則是不同接口的request對象, 從協調server通知分支事務提交的分析
而sendSynRequest的代碼處理:
private Object sendAsyncRequest(String address, Channel channel, Object msg, long timeout)
throws TimeoutException {
if (channel == null) {
LOGGER.warn("sendAsyncRequestWithResponse nothing, caused by null channel.");
return null;
}
final RpcMessage rpcMessage = new RpcMessage();
rpcMessage.setId(RpcMessage.getNextMessageId());
rpcMessage.setAsync(false);
rpcMessage.setHeartbeat(false);
rpcMessage.setRequest(true);
rpcMessage.setBody(msg);
final MessageFuture messageFuture = new MessageFuture();
messageFuture.setRequestMessage(rpcMessage);
messageFuture.setTimeout(timeout);
futures.put(rpcMessage.getId(), messageFuture);
if (address != null) {
ConcurrentHashMap<String, BlockingQueue<RpcMessage>> map = basketMap;
BlockingQueue<RpcMessage> basket = map.get(address);
if (basket == null) {
map.putIfAbsent(address, new LinkedBlockingQueue<RpcMessage>());
basket = map.get(address);
}
basket.offer(rpcMessage);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("offer message: " + rpcMessage.getBody());
}
if (!isSending) {
synchronized (mergeLock) {
mergeLock.notifyAll();
}
}
} else {
ChannelFuture future;
channelWriteableCheck(channel, msg);
future = channel.writeAndFlush(rpcMessage);
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
if (!future.isSuccess()) {
MessageFuture messageFuture = futures.remove(rpcMessage.getId());
if (messageFuture != null) {
messageFuture.setResultMessage(future.cause());
}
destroyChannel(future.channel());
}
}
});
}
if (timeout > 0) {
try {
return messageFuture.get(timeout, TimeUnit.MILLISECONDS);
} catch (Exception exx) {
LOGGER.error("wait response error:" + exx.getMessage() + ",ip:" + address + ",request:" + msg);
if (exx instanceof TimeoutException) {
throw (TimeoutException)exx;
} else {
throw new RuntimeException(exx);
}
}
} else {
return null;
}
}
可以看到接口的request放入body後再分裝成MessageFuture(增加超時信息),然後rpc msg通過netty的ChannelFuture發送出去。
序列化
這裏序列化用的java的序列化接口,部分request和reposne重寫encode和decode來控制,例如AbstractBranchEndRequest
@Override
public byte[] encode() {
byte[] applicationDataBytes = null;
if (this.applicationData != null) {
applicationDataBytes = applicationData.getBytes(UTF8);
if (applicationDataBytes.length > 512) {
byteBuffer = ByteBuffer.allocate(applicationDataBytes.length + 1024);
}
}
// 1. xid
if (this.xid != null) {
byte[] bs = xid.getBytes(UTF8);
byteBuffer.putShort((short) bs.length);
if (bs.length > 0) {
byteBuffer.put(bs);
}
} else {
byteBuffer.putShort((short) 0);
}
// 2. Branch Id
byteBuffer.putLong(this.branchId);
// 3. Branch Type
byteBuffer.put((byte) this.branchType.ordinal());
// 4. Resource Id
if (this.resourceId != null) {
byte[] bs = resourceId.getBytes(UTF8);
byteBuffer.putShort((short) bs.length);
if (bs.length > 0) {
byteBuffer.put(bs);
}
} else {
byteBuffer.putShort((short) 0);
}
// 5. Application Data
if (this.applicationData != null) {
byteBuffer.putInt(applicationDataBytes.length);
if (applicationDataBytes.length > 0) {
byteBuffer.put(applicationDataBytes);
}
} else {
byteBuffer.putInt(0);
}
byteBuffer.flip();
byte[] content = new byte[byteBuffer.limit()];
byteBuffer.get(content);
return content;
}
@Override
public boolean decode(ByteBuf in) {
int leftLen = in.readableBytes();
int read = 0;
int xidLen = in.readShort();
if (xidLen > 0) {
if (leftLen < xidLen) {
return false;
}
byte[] bs = new byte[xidLen];
in.readBytes(bs);
setXid(new String(bs, UTF8));
leftLen -= xidLen;
}
this.branchId = in.readLong();
leftLen -= 8;
this.branchType = BranchType.get(in.readByte());
leftLen --;
int resourceIdLen = in.readShort();
if (resourceIdLen > 0) {
if (leftLen < resourceIdLen) {
return false;
}
byte[] bs = new byte[resourceIdLen];
in.readBytes(bs);
setResourceId(new String(bs, UTF8));
leftLen -= resourceIdLen;
}
int applicationDataLen = in.readShort();
if (applicationDataLen > 0) {
if (leftLen < applicationDataLen) {
return false;
}
byte[] bs = new byte[applicationDataLen];
in.readBytes(bs);
setApplicationData(new String(bs, UTF8));
leftLen -= applicationDataLen;
}
return true;
}
業務方法的映射
網絡通信和message的序列化已經完備, 還剩一個就是message request映射到業務方法並組成reponse返回。 從server收到消息看,是DefaultServerMessageListenerImpl
這裏的handler就負責映射業務的處理,這裏handler也指向DefaultCoordinator的onRequest
@Override
public AbstractResultMessage onRequest(AbstractMessage request, RpcContext context) {
if (!(request instanceof AbstractTransactionRequestToTC)) {
throw new IllegalArgumentException();
}
AbstractTransactionRequestToTC transactionRequest = (AbstractTransactionRequestToTC) request;
transactionRequest.setTCInboundHandler(this);
return transactionRequest.handle(context);
}
可以看到最終的業務處理都放在request的handler方法完成。 我們拿其中一個request看看
例如BranchRollbackRequest,繼承AbstractTransactionRequestToRM,而request的handler方法執行類是RMInboundHandler來執行, 可以看到
@Override
public BranchCommitResponse handle(BranchCommitRequest request) {
BranchCommitResponse response = new BranchCommitResponse();
exceptionHandleTemplate(new Callback<BranchCommitRequest, BranchCommitResponse>() {
@Override
public void execute(BranchCommitRequest request, BranchCommitResponse response) throws TransactionException {
doBranchCommit(request, response);
}
}, request, response);
return response;
}
至此,整個基於message request,response的rpc就完成了, 當然真正的rpc還有更多模塊,例如服務的自注冊與發行, 服務監控, 服務調度等。
文章到此結束,不想文章太長,主要分析fescar主要功能原理相關的代碼, 而fescar還有其他未有提及。