`
george.gu
  • 浏览: 70971 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

AOP(1):应用中的几个小故事

阅读更多

I had heared about AOP almost 7 years but only used it in two projects. 7 Years, I still only know few about AOP, if i were not involved in that two projects, i would still know that few.

The fact is always like that:

 

  1. Hear about it.
  2. Know how to use it.
  3. Use it in project
  4. Know what's problem it solved and try to enhance it.

First story: Why there is no "before" or "after" method execution Advice?

Normally for a AOP, we can say there are point-cuts or events:

 

  1. Befroe execution
  2. Before return
  3. Exception catch and processing in case exception raised

First time, I use AOP with EJB3. Thanks to annotation @Interceptor and @AroudInvoke, i can define AOP interceptors easily. But for a long time during, I was always wondering:

 

  • Why there is only "around " invokea method, but no "before" or "after" invoke methods?
In fact, AOP engine already get the hand from execution environment and give you the hand to execute the methods, so you can do whatever you want: before the method execution, after methods execution or catch and process the exception. Please remember to return the execution result in order to launch the successive interceptor chain or return the control to execution environment.

What's more, in fact there are dedicated before, throws and after returning advice(interceptor) in spring AOP.  

Second story: Exception used as logical condition had been intercepted by prior interceptor

There is one advisor to manage transaction, its main usage as following:
  1. Catch Exception from point-cut and retry execution in case there is exception.
  2. If max retry number catched, marks Transaction to be "Rollback Only".
Here is the snapshot for tx-advice defintion :

  <tx:advice id="tx-advice" transaction-manager="myTransactionManager">

      <tx:attributes>

          <tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>

      </tx:attributes>

  </tx:advice>

 

  <bean id="myTransactionManager"

                class="org.springframework.orm.hibernate3.HibernateTransactionManager">

        <property name="sessionFactory">

            <ref bean="mySessionFactory"/>

        </property>

  </bean>

 

 

  <bean id="TransactionRetryInterceptor"

        class="com.MyTransactionRetryInterceptor"/>

 

Here is the shanpshot for MyTransactionRetryInterceptor: 

 

    public Object invoke(MethodInvocation invocation) throws Throwable {

        int retryCount = 0;

        logger.info("TRANSACTION BEGIN");

        while (true) {

            try {

                ReflectiveMethodInvocation inv =

                                                                                (ReflectiveMethodInvocation) invocation;

                MethodInvocation anotherInvocation = inv.invocableClone();

                Object obj = anotherInvocation.proceed();

                 logger.info("TRANSACTION END: OK");

                 return obj;

            } catch (Exception ex) {

                // If reached maximum number of retries then just rethrow this exception immediately.

                if (++retryCount > maxRetryCount) {

                      logger.error ("TRANSACTION FAIL: max retries reached:", ex);

                      throw ex;

                }

 

                //TODO...check if the transaction need to be retried, if yes, retry it. Otherwise, // throw the exception directly.

             }

 

             // Clean-up & delay for a while before retrying.

             cleanupBeforeRetrying();

             delay();

        }

    }


I define point-cuts on both class A and class B. Main behavior of B:
  1. call A.dosomething() to execute some logical.
  2. If A.dosomething() raise exception C, that means some special case happen, B should process dedicated use case.
When i launch the application, it always warn Transaction rollback. It makes my confuse for a period. If we study what happen behind, we can get the following procedure:
  1. Class B invoke Class A to do something.
  2. Intercaptor will catch the exception C raised by A and mark Transaction "rollback only" once reach max retry number.
  3. Intercaptor delegate exception C to class B,
  4. Class B executed completely and try to submit the Transaction.
  5. Transaction rollback as it is marked "Rollback Only".
So I have to redesign the business logical:
  1. Do not set point-cut on class A.
  2. Or do not use exception as business logical condition.
  3. Or use some other adapter who provide same behavior but has no that transaction interceptor. It is like first workaround.
Third Story: It is really difficulty to debug impossible NullPointerException raised because of not-well defined interceptor. 
It is like second story, but it makes situation more complex:
  • There are some Interceptors/Advisors which are not defined by myself.
So if other people define new interceptors for the classes I am working on, it will be difficulty to identify the error in integration test stage.


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics