Saturday, August 9, 2014

Spring AOP: Excluding Methods in Pointcuts

We use Spring AOP to make use of aspects in our applications for the purpose of recording statistics about requests they receive. This approach has worked out well because it helps separate the concern of tracking statistics from our business logic. Previous iterations of our applications mixed the two, leaing to code that was generally harder to maintain.

Below is an example of how we might configure an aspect to target all entry points into our business application with the same aspect:

    <aop:config>
        <aop:pointcut id="requestPointcut"
                      expression="execution(public * org.company.service.*.*(..))"/>
        <aop:aspect id="requestAspect" ref="requestStatAspect">
            <aop:around method="around" pointcut-ref="requestPointcut"/>
        </aop:aspect>
    </aop:config>

    <bean id="requestAspect" class="org.company.service.aop.RequestIdentifierAspect" lazy-init="true"/>

With the above, we are saying we want request identifiers managed for every request to our interfaces. With the wildcards in the expression, we are saying target every class in the org.mycompany.myapp.service package and every method in those classes.

This approach worked greatly until we added an interface that provided health reporting for system monitoring purposes. This method lived in a new interface. Let's suppose added the interface method is defined as:

  • public boolean org.company.HealthService.isHealthy()
    

Since the method signature is different (it takes no arguments), running the advice in the aspect would lead to errors as the aspect evaluated the method arguments. We could change the code in the aspect to avoid processing if the arguments contained within the join point do not match what we are expecting. This approach is not that attractive because it one, involves changing code for special cases, and two, could lead to the aspect siltently not invoking its main logic at times we might not expect. If we target a method with the aspect unintentionally, we want to be informed by errors in our log.

An alternative we found was to exclude the new method from the pointcut expression:

  • execution(public * org.company.service.*.*(..)) &amp;&amp; !execution(* org.company.service.HealthService.*(..))
    

Just with adding special case logic to an aspect or code in general to avoid exception cases, we have to be careful that the exceptional cases we avoid targeting with the aspect does not get out of hand as we are tempted to add more in the future.

No comments:

Post a Comment