views:

189

answers:

2

I am trying to use AOP to do some processing after an annotated controller. Everything is running with no errors, but the advice is not being executed.

Here is the controller code:

@Controller
public class HomeController {       
    @RequestMapping("/home.fo")
    public String home(ModelMap model) {
        model = new ModelMap();
        return "home";
    }   
}

and the setup in application-config

<aop:aspectj-autoproxy/>

<bean id="testAdvice" class="com.test.TestAdvice">
</bean>

<bean id="testAdvisor"
    class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
    <property name="advice" ref="testAdvice" />
    <property name="expression" value="execution(* *.home(..))" />
</bean>

and the actual advice

public class TestAdvice implements AfterReturningAdvice {

    protected final Log logger = LogFactory.getLog(getClass());

    public void afterReturning(Object returnValue, Method method, Object[] args,
            Object target) throws Throwable {
        logger.info("Called after returning advice!");
    }
}

Is it even possible to have advice on annotated controllers? I am using Spring 2.5.

A: 

For MVC controllers the preferred method of accomplishing what you are trying to do is to use interceptors. See http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-handlermapping-interceptor

Sasi
I disagree. Aspects are arguably a more elegant way to achieving the same thing.
skaffman
My general rule is use interceptors when you want to intercept certain web requests. Use Aspects when you want to intercept methods on normal spring beans. Since the question is related to intercepting Controllers (which are mapped to web requests), using interceptors is more suited.
Sasi
+2  A: 

It's possible to have advice on annotated controllers.

I assume you want to advice after execution of all methods in classes annotated with @Controller.

Here's an example:

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class ControllerAspect {

    @Pointcut("within(@org.springframework.stereotype.Controller *)")
    public void controllerBean() {}

    @Pointcut("execution(* *(..))")
    public void methodPointcut() {}

    @AfterReturning("controllerBean() && methodPointcut() ")
    public void afterMethodInControllerClass() {
        System.out.println("after advice..");
    }
}

If you want to use Spring AOP with AspectJ syntax, you also need a configuration file like this:

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


    <bean id="controllerAspect" class="controller.ControllerAspect" />

    <aop:aspectj-autoproxy>
        <aop:include name="controllerAspect" />
    </aop:aspectj-autoproxy>
</beans>

Note: With Spring AOP, the Spring container will only weave Spring beans. If the @Controller object isn't a Spring bean, you must use AspectJ weaving.

Espen
How do I tell if the the @Controller is a bean? I know it is correctly receiving dependencies through @Autowired, so I thought it was a bean, but I am still having problems getting the aspect to execute.
jdana
If the autowiring works and you don't have another IOC container than Spring, then it is a Spring bean.
Espen