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:
- Hear about it.
- Know how to use it.
- Use it in project
- 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:
- Befroe execution
- Before return
- 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?
Second story: Exception used as logical condition had been intercepted by prior interceptor
- Catch Exception from point-cut and retry execution in case there is exception.
- If max retry number catched, marks Transaction to be "Rollback Only".
<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(); } } |
- call A.dosomething() to execute some logical.
- If A.dosomething() raise exception C, that means some special case happen, B should process dedicated use case.
- Class B invoke Class A to do something.
- Intercaptor will catch the exception C raised by A and mark Transaction "rollback only" once reach max retry number.
- Intercaptor delegate exception C to class B,
- Class B executed completely and try to submit the Transaction.
- Transaction rollback as it is marked "Rollback Only".
- Do not set point-cut on class A.
- Or do not use exception as business logical condition.
- Or use some other adapter who provide same behavior but has no that transaction interceptor. It is like first workaround.
- There are some Interceptors/Advisors which are not defined by myself.