SpringMVC+Mybatis+事務ロール+異常パッケージを返します.


問題の背景:
  • Dbbを使って分散サービスアーキテクチャを構築し、serviceの実現にSpringMVC 4.1.6+MyBatis 3.2.8を採用する.
  • は一つの次元を守るために、serviceインターフェースを汎用的に定義し、即ち業務の変化をさせ、定義されたserviceインターフェースに影響を与えないようにする.
  • 最終Serviceの方法署名は、以下のように定義されている(例).
    public ServiceResoult addProduct(ServiceParam)
    そのうち
    ServiceResoultの定義は以下の通りです.
    public class ServiceResult {
        private T result;
        /**
        *     code
        */
        private int retCode;  
        public int getRetCode() {
            return retCode;
        }
        public void setRetCode(int retCode) {
            this.retCode = retCode;
        }
        public T getResult() {
            return result;
        }
        public void setResult(T result) {
            this.result = result;
        }
    }
    ここでServiceParamの定義は以下の通りである.
    public class ServiceParam {
        private T param;
    
        public T getParam() {
            return param;
        }
    
        public void setParam(T param) {
            this.param = param;
        }
    }
    この方法の署名は、リモート呼び出しの両端のトラフィックの変化が、インターフェースに影響を与えないことを保証します.キャリブレーションの減量を実現しました.
    その中で、ServiceResoultはすべての業務と運転異常をカプセル化し、これをerrorCodeに変えて返します.このように、異常な遠隔伝送の消費が減少し、両端の異常結合を呼び出しても、入れ子の異常な獲得ブロックにおける呼び出し側の業務処理の気まずさが回避される.
    しかし、実際の枠組みの中で、このような問題が発見されました.
    addProductメソッドの事務は、Springによって管理されると、異常を捨てて事務のロールバックをしなければならない.もし方法が異常を投げたら(転用者にとってはリモート異常です)、異常をerrorCodeに転化して出力する目的を満たしてくれません.
    したがって、我々は異常な捕獲をerrorCodeに変える方法を考えなければならない.同時に、業務のロールバックにも影響しない.何回もの試みを経て、やっとこの問題を円満に解決しました.ここに記録を共有します.
    次は私の考え方と解決方法です.
    Springを使って事務を管理している以上、関連サービスをAOPでブロックし、業務のロールバック後に異常を捉え続け、この異常を転化出力します.
    第一歩、AOPブロックを作る
    @Aspect
    @Component
    @Order(0)  
    public class ExceptionAspect {
        /**
         *      ,       ,                      
         */
        @Pointcut("execution(* cn.xx.dubbo.security.service..*(..))")
        public void aspect() {
        }
    
        @Around("aspect()")
        public ServiceResult around(JoinPoint joinPoint) {
            System.out.println("===============START");
            ServiceResult result;
            try {
                //         
                result = (ServiceResult) ((ProceedingJoinPoint) joinPoint).proceed();
            } catch (Throwable e) {
                System.out.println("     :" + e.getMessage());
                result = new ServiceResult();
                result.setResult("exception:" + e.getMessage());
                result.setRetCode(-1);
            }
    
            System.out.println("===============END");
            return result;
        }
    }
    このクラスでは、接面実行の順序Order(0)、すなわち最外層が定義される.
    第二に、注釈を使ってサービス方法を事務定義し、サービス方法に業務異常を投げて、事務をロールバックさせる.
     
     @Override
        @Transactional
        public ServiceResult addProduct(ServiceParam param) throws Exception {
            Product product = param.getParam();
            int rlt = biz.addProduct(product);
            if(rlt == 0)
                throw new Exception("    !");
            else {
                ServiceResult result = new ServiceResult();
                result.setResult(rlt);
                return result;
            }
        }
    ステップ3で、Springプロファイルを修正します.
     
     
    最後にJunnitでこのservice方法をテストします.この方法は異常を投げても、最外層の
    Exception Aspect
     この異常をブロックして、仕事が正確にロールバックした後、異常を発生させます.
    errorCodeに変換し、ServiceResultにパッケージ化して成功裏に戻り、改造に成功しました.