ずっと前、おそらく作品seata分散トランザクションモードを見ていない、レコードは今、それがどのように動作するかを見て。
次のようにあなたが登録センターとseata管理サービス、および分散トランザクションを3つのクライアントをシミュレートする必要性を開始するための最初の必要性、プロジェクトが構成されているので、プロジェクトのデバッグは、非常に面倒である(図パイレーツA)
TC:トランザクション管理センターが提供seata。
TM:成功を伝えるTCトランザクションの発信、そして最終的にかどうかトランザクション
RM:究極のリソースマネージャである単一のマイクロサービス、
実はこの絵は非常に適切ではない、一般的なビジネスプロセスは、別のビジネスのtm表示されていませんが、実際には、プロセスでよりフィット感を時間順に作成する必要があり、我々はまた、トランザクションを開始し、最終的には他の通じますそれは、TMがRMで役立つはずであるためであるようなサービスは、ロールバックに提出を判断するための情報を返しますが、私は右、そして、それを描画しません。
私たちのパラメータ、データソースの代理店外に設定seataに加えて、モードで使用します。ちょうどその取引を行うためにここにその治療、GlobalTransactionScannerこの注釈プロキシメソッドを見て、トランザクション制御方法は、それをする必要が上@GlobalTranscationのコメントを追加するには、我々はこのクラスの焦点を見ています。
その継承にまず見て、
パブリッククラスGlobalTransactionScannerはAbstractAutoProxyCreatorを拡張します 道具InitializingBean、ApplicationContextAware、 DisposableBean
それはAbstractAutoPrxoyCreatorはAOPを達成するために使用された継承し、継承InitializingBean、ApplicationContextAware、DisposableBeanいくつかの初期のSpring Beanフック関数を処理します。
InitClient方法は、フックに関数に呼び出されたafterPropertiesSet
プライベート無効initClient(){ もし(LOGGER .isInfoEnabled()){ LOGGERの.info( "初期化グローバル・トランザクションクライアント..."); } IF(のStringUtils。isNullOrEmpty(アプリケーションID)||のStringUtils。isNullOrEmpty(txServiceGroup)){ (新しいIllegalArgumentExceptionをスローし "APPLICATIONID:" + APPLICATIONID + "txServiceGroup:" + txServiceGroup)。 } //初期化はここでは、TMアドレスレジストリや初期化TCP接続することによって得られる TMClient。INIT(APPLICATIONID、txServiceGroup)。 IF(LOGGER .isInfoEnabled()){ LOGGERの.info( "トランザクション・マネージャー・クライアントが初期化される。APPLICATIONID [" + APPLICATIONID + "] txServiceGroup [" + txServiceGroup + "]"); } //同上RMClient。INIT(アプリケーションID、txServiceGroup)。 IF(LOGGER .isInfoEnabled()){ LOGGERの.info( "リソース・マネージャが初期化されます。APPLICATIONID [" + APPLICATIONID + "] txServiceGroup [" + txServiceGroup + "]"); } もし(LOGGER .isInfoEnabled()){ LOGGERの.info( "グローバル・トランザクションのクライアントが初期化されます。"); } registerSpringShutdownHook(); }
そして、この方法を書き換える見wrapIfNecessary
@オーバーライド 保護オブジェクトwrapIfNecessary(オブジェクト・ビーン、文字列のbeanName、オブジェクトcacheKey){ IF(disableGlobalTransaction){ Beanを返します。 } {試します 同期(PROXYED_SET){ IF(PROXYED_SETの .contains(のbeanName)){ Beanを返します。 } インターセプター= NULL; //使用TCC模式場合(TCCBeanParserUtils isTccAutoProxy(豆、のbeanName、ApplicationContextの)){インターセプター=新しいTccActionInterceptor(TCCBeanParserUtils。getRemotingDesc(のbeanName))。 } そうしないと { クラス<?> serviceInterface = SpringProxyUtils。findTargetClass(豆)。 クラス<?> [] interfacesIfJdk = SpringProxyUtils。findInterfaces(豆)。 (もし!existsAnnotation(新しいクラス[] {} serviceInterface) &&!existsAnnotation(interfacesIfJdk)){ Beanを返します。 } IF(インターセプター== NULL){ インターセプター=新しいGlobalTransactionalInterceptor(failureHandlerHook)。 } } LOGGERの.info( "ビーン[" + bean.getClassは()。のgetName()+ "]名前の[" +のbeanName + "]は[インターセプターを使用します" + interceptor.getClass()のgetName()+ "]")。 (!のAopUtils。もしisAopProxy(豆)){ //親クラスのメソッドを実行します = super.wrapIfNecessary妻(妻のbeanName、cacheKey)。 } そうしないと { // 取得豆の助言 。AdvisedSupportに助言= SpringProxyUtils getAdvisedSupport(豆)。 //お勧めのパッケージ顧問 アドバイザ[]アドバイザ= buildAdvisors(のbeanName、getAdvicesAndAdvisorsForBean(NULL、NULL、NULL))。 {(顧問AVRアドバイザ)のために advised.addAdvisor(0、AVR)。 } } PROXYED_SETは(のbeanName).add。 Beanを返します。 } }キャッチ(例外EXX){ 新しいのRuntimeException(EXX)を投げます。 } }
postProcessBeforeInitializationで、データソースを処理するための
パブリックオブジェクトpostProcessBeforeInitialization(オブジェクト・ビーン、文字列のbeanName)がBeansExceptionを{スロー // Beanがデータソースではなくseata代理店いいです場合 もし(豆のDataSource &&!DataSourceProxyのinstanceof(豆)&& ConfigurationFactoryのinstanceof。のgetInstance().getBoolean(DATASOURCE_AUTOPROXY、偽)){ IF(LOGGER .isInfoEnabled()){ LOGGERの.info( "の自動プロキシ[" +のbeanName + "]"); } DataSourceProxy dataSourceProxy = DataSourceProxyHolder。取得().putDataSource((データソース)豆); // CGLIBによって強化 エンハンサーを返します。作成(bean.getClass()、(org.springframework.cglib.proxy.MethodInterceptor)(O、メソッド、引数、methodProxy) - > { 方法M = 々 BeanUtils。findDeclaredMethod(DataSourceProxy.class、method.getName()、method.getParameterTypes())。 IF(NULL!= M){ m.invoke(dataSourceProxy、引数)を返します。 } そうしないと { ブールoldAccessible = method.isAccessible()。 {試します method.setAccessible(真の); method.invoke(豆、引数)を返します。 } 最後に { //セキュリティ上の理由のために、元のアクセスを回復 method.setAccessible(oldAccessible)。 } } }); } Beanを返します。 }
実際には、ほとんど知識の春、見た目があまりにも長い間忘れていたので、なぜ、ここで再びそれを言うので、復習のこの時期。実際には、実際の作業はまだGlobalTransactionalInterceptor、その後、我々は再びそれを分析しています
@オーバーライド パブリックオブジェクトを呼び出し(最終MethodInvocation methodInvocationは)のThrowableを{スロー <?>クラスtargetClass =(!?。methodInvocation.getThis()= nullをAopUtils getTargetClass(methodInvocation.getThis()):NULL); この方法specificMethodはClassUtilsを=。getMostSpecificMethod(methodInvocation.getMethod()、targetClass)。 最終的なメソッド方法= BridgeMethodResolver。findBridgedMethod(specificMethod)。 最終GlobalTransactional globalTransactionalAnnotation = getAnnotation(方法GlobalTransactional.class)。 最終GlobalLock globalLockAnnotation = getAnnotation(方法GlobalLock.class)。 もし(globalTransactionalAnnotation!= NULL){ handleGlobalTransaction(methodInvocation、globalTransactionalAnnotation)を返します。 }それ以外の場合(globalLockAnnotation!= NULL){ リターンhandleGlobalLock(methodInvocation)。 } そうしないと { リターンmethodInvocation.proceed(); } }
方法は、ロジックに異なる注釈た呼び出すためによると、我々は、実行handleGlobalTranscationのフォーカス方式を見て
プライベートオブジェクトhandleGlobalTransaction(最終MethodInvocation methodInvocation、 最終GlobalTransactional globalTrxAnno)は{たThrowableをスロー {試します 渡されたexecutorを実行1.transactionalTemplate リターンtransactionalTemplate.execute(新TransactionalExecutor(){ @オーバーライド パブリックオブジェクトの実行()は、のThrowableを{スロー リターンmethodInvocation.proceed(); } パブリック文字列名(){ 文字列名= globalTrxAnno.name()。 (!ののStringUtils。もしisNullOrEmpty(名)){ 名前を返します。 } リターンformatMethod(methodInvocation.getMethod()); } //の情報トランザクションを取得します。 @オーバーライド 公共TransactionInfo getTransactionInfo(){ TransactionInfo transactionInfo =新しいTransactionInfo(); transactionInfo.setTimeOut(globalTrxAnno.timeoutMills())。 transactionInfo.setName(名()); セット<RollbackRule> rollbackRules =新しいLinkedHashSetの<>(); 用(クラスrbRule <?>:globalTrxAnno.rollbackFor()){ rollbackRules.add(新しいRollbackRule(rbRule)); } {(globalTrxAnno.rollbackForClassName()文字列rbRule)のために rollbackRules.add(新しいRollbackRule(rbRule)); } 用(クラスrbRule <?>:globalTrxAnno.noRollbackFor()){ rollbackRules.add(新しいNoRollbackRule(rbRule)); } {(globalTrxAnno.noRollbackForClassName()文字列rbRule)のために rollbackRules.add(新しいNoRollbackRule(rbRule)); } transactionInfo.setRollbackRules(rollbackRules)。 transactionInfoを返します。 } }); 解決トランザクションエラーに2分類 }キャッチ(TransactionalExecutor.ExecutionException電子){ TransactionalExecutor.Codeコード= e.getCode()。 スイッチ(コード){ ケースRollbackDone: e.getOriginalExceptionを()スロー; ケースBeginFailure: failureHandler.onBeginFailure(e.getTransaction()、e.getCause())。 e.getCauseを()スロー; ケースCommitFailure: failureHandler.onCommitFailure(e.getTransaction()、e.getCause())。 e.getCauseを()スロー; ケースRollbackFailure: failureHandler.onRollbackFailure(e.getTransaction()、e.getCause())。 e.getCauseを()スロー; デフォルト: 新しいShouldNeverHappenException( "不明TransactionalExecutor.Code:" +コード)を投げます。 } } }
実際には、実際の作業は、それが乾燥するために1のままであります
オブジェクトの実行パブリック(TransactionalExecutor事業)のThrowableを{スロー //新しいトランザクション1.1作成 GlobalTransaction TX =のGlobalTransactionContext。getCurrentOrCreateを(); 1.2 //得る取引情報 TransactionInfo txInfo = business.getTransactionInfo()。 IF(txInfo == NULL){ (「transactionInfoが存在しない」)新しいShouldNeverHappenExceptionを投げます。 } {試します 1.3 //トランザクションのbeginTransaction(txInfo、TX)を開始します。 オブジェクトrs = NULL; {試します //業務執行RS = business.execute(); }キャッチ(ThrowableのEX){ ロールバック操作completeTransactionAfterThrowing(txInfo、TX、EX)に取り扱い1.4 //例外。 EXを投げます。 } //トランザクションのコミット のcommitTransaction(TX)を、 RSを返します。 } 最後に { //フック関数の実行 )(triggerAfterCompletionを。 掃除(); } }
1.1 GlobalTranscationを作成し、XIDが、この時点で生成されていない、nullであります
DefaultGlobalTransaction(文字列XID、GlobalStatus状態、GlobalTransactionRoleロール){ this.transactionManager = TransactionManagerHolder。取得(); this.xid = XID; this.status =ステータス。 this.role =役割。 }
1.2取引に基づいて取得されますが、いくつかの構成情報、ロールバックルール、タイムアウト、などを指摘します
公共TransactionInfo getTransactionInfo(){ TransactionInfo transactionInfo =新しいTransactionInfo(); transactionInfo.setTimeOut(globalTrxAnno.timeoutMills())。 transactionInfo.setName(名()); セット<RollbackRule> rollbackRules =新しいLinkedHashSetの<>(); 用(クラスrbRule <?>:globalTrxAnno.rollbackFor()){ rollbackRules.add(新しいRollbackRule(rbRule)); } {(globalTrxAnno.rollbackForClassName()文字列rbRule)のために rollbackRules.add(新しいRollbackRule(rbRule)); } 用(クラスrbRule <?>:globalTrxAnno.noRollbackFor()){ rollbackRules.add(新しいNoRollbackRule(rbRule)); } {(globalTrxAnno.noRollbackForClassName()文字列rbRule)のために rollbackRules.add(新しいNoRollbackRule(rbRule)); } transactionInfo.setRollbackRules(rollbackRules)。 transactionInfoを返します。 }
1.3トランザクションを開始
公共の文字列が始まる(文字列APPLICATIONID、文字transactionServiceGroup、列名、int型のタイムアウト) スローTransactionException { //新しいトランザクション開始要求を作成します。 GlobalBeginRequest要求=新しいGlobalBeginRequest(); request.setTransactionName(名); request.setTimeout(タイムアウト)。 //戻り値を取得します。 GlobalBeginResponse応答=(GlobalBeginResponse)syncCall(リクエスト)。 IF(response.getResultCode()==のResultCode。失敗){ スロー新しいTmTransactionException(TransactionExceptionCode。BeginFailed、response.getMsg()); } // XIDを返します。 リターンresponse.getXid(); }
1.4ロールバックトランザクション
空completeTransactionAfterThrowingプライベート(TransactionInfo txInfo、GlobalTransactionのTX、ThrowableのEXは)TransactionalExecutor.ExecutionException {スロー //をトランザクションのロールバック情報と情報のマッチングなしの場合 であれば(txInfo!= nullの&& txInfo.rollbackOn (EX)){ {試します //ロールバック操作 rollbackTransaction(TX、EX); }キャッチ(TransactionExceptionのTXE){ //ここでは、ロールバック操作はまた、トランザクションがロールバック回数を設定することができます構成で失敗する可能性があり 、新しいTransactionalExecutor.ExecutionException(TX、TXEをスローします TransactionalExecutor.Code。RollbackFailure、EX); } } そうしないと { //提出 のcommitTransaction(TX)を、 } }