Ordering aspects with Spring AOP && MVC

Marat Asadurian picture Marat Asadurian · Jan 29, 2012 · Viewed 20.6k times · Source

I am trying to use Spring AOP with Spring MVC Controller. I have 3 aspects, and want the to be in specific order. In order to do this, I use Ordered interface and implement getOrder method:

@Aspect
@Component
public class LoggingAspect implements Ordered{

public int getOrder() {
System.out.println("Abra");
return 1;
}

Adviced class:

@Component
@Controller
public class HomeController {   

Pointcuts:

@Aspect
public class SystemArchitecture {

    @Pointcut("execution (* com.jajah.StorageManager.HomeController.*(..))")
    public void inHomeController(){}

    @Pointcut("execution (* com.jajah.StorageManager.HomeController.*(..))")
    public void loggable(){}

    @Pointcut("execution (* com.jajah.StorageManager.HomeController.*(..))")
    public void authenticated(){}

}

Configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"   
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <annotation-driven />
    <context:annotation-config /> 
    <aop:aspectj-autoproxy proxy-target-class="false"/>

    <beans:bean id="AuthenticationAspect" class="com.jajah.CommonAspects.SecurityAspects.OAuthAspect"/>
    <beans:bean id="ErrorHandlingAspect" class="com.jajah.StorageManager.Aspects.ErrorHandlingAspect"/>


    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
    <!-- <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />

    </beans:bean> -->

    <beans:bean name="homeController" class="com.jajah.StorageManager.HomeController">
        <beans:constructor-arg>     
            <beans:ref bean="CloudStorage"/>
        </beans:constructor-arg>
        <beans:constructor-arg>     
            <beans:ref bean="ConfigurationContainer"/>
        </beans:constructor-arg>
    </beans:bean>

    <beans:bean id="CloudStorage" name="CloudStorage"       class="com.jajah.StorageManager.CloudStorageProxy"      scope="singleton">
        <beans:constructor-arg>     
         <beans:ref bean="ConfigurationContainer"/>
        </beans:constructor-arg>
    </beans:bean>

    <beans:bean id ="ConfigurationContainer" class="com.jajah.StorageManager.ConfigurationContainer" scope="singleton"/>





</beans:beans>

The getOrder doesn't do the trick. I will appreciate any practical advice, or if you don't have the exact answer I will appreciate any theoretical knowledge about the Spring Proxy and the weaving mechanism.

I will post any Code/Configuration required upon demand. Thanks for reading.

Update: 1. I tried @Order(1) with same result. 2. I tried to move aspects to same package, it changed their order, but I still couldn't control it.

Answer

danny.lesnik picture danny.lesnik · Jan 29, 2012

You don't need to implement Ordered interface.

In Spring AOP you can do things much easier.

@Aspect
@Order(1)
public class AspectA
{
  @Before("............")
   public void doit() {}
}

@Aspect
@Order(2)
public class AspectB
{
  @Before(".............")
  public void doit() {}
} 

Update:

@Aspect
@Order(1)
public class SpringAspect {

    @Pointcut("within(com.vanilla.service.MyService+)")
    public void businessLogicMethods(){}

     @Around("businessLogicMethods()")
     public Object profile(ProceedingJoinPoint pjp) throws Throwable {
             System.out.println("running Advice #1");   
         Object output = pjp.proceed();
         return output;
     }
}

@Aspect
@Order(2)
public class SpringAspect2 {

    @Pointcut("within(com.vanilla.service.MyService+)")
    public void businessLogicMethods(){}

     @Around("businessLogicMethods()")
     public Object profile(ProceedingJoinPoint pjp) throws Throwable {
             System.out.println("running Advice #2");   
         Object output = pjp.proceed();
         return output;
     }
}

Now the application Context Configuration XML:

<context:annotation-config />
<aop:aspectj-autoproxy />

  <bean id="springAspect" class="com.vanilla.aspect.SpringAspect" />
    <bean id="springAspect2" class="com.vanilla.aspect.SpringAspect2" />

You need to enable AOP proxy by:

<aop:aspectj-autoproxy />

otherwise no advice will be activated.

Update 2:

I just make a research on this issue. @order annotation works only on Spring's based proxy AOP (Which I'm using in my example). Accoridng to documentation if you are using weaving you should use declare precedence option.

Update 3

  1. I don't see any advices in your code, just aspects and pointcuts.
  2. If your Advice classes are: x.y.z.SystemArchitecture

then you need to configure it at as

<bean id="systemArchitecture" class="x.y.z.SystemArchitecture" /> 

and I don't see it in your code.

  1. "execution (* com.jajah.StorageManager.HomeController.*(..))" what are you targeting on? Can you write it using words?

Anyway. Please drop me a message on facebook and I'll send you working example which does exactly what are you trying to do.