20

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.

2
  • I never was able to get this to work, and unfortunately, I have run out of time to be able to work on it. For now I am having to stick with just copying the code. Commented Jul 29, 2010 at 20:33
  • You need to include your testAdvisor bean in <aop:aspectj-autoproxy/> like this: <aop:include name="testAdvisor"/> Commented Feb 25, 2016 at 21:28

4 Answers 4

23

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"> <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.

Sign up to request clarification or add additional context in comments.

3 Comments

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.
If the autowiring works and you don't have another IOC container than Spring, then it is a Spring bean.
My other components work fine with aspect but no luck for controllers. In the same aspect class, I define controller pointcuts and also service pointcuts. service pointcuts work but controllers' not. Is there any clue about why this happens?
2

I had the same problem where advice for Repository was working, but advice for Controller was not. Finally I found a solution. In short, you need to make sure your AOP definition is loaded in Servlet context, not a different context.

In my case, my Spring AOP definition is defined in tools-config.xml. After moving it from here

<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/tools-config.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 

to here,

<servlet> <servlet-name>petclinic</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/mvc-core-config.xml, classpath:spring/tools-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> 

the advice for Controller is working.

1 Comment

What if everything is via annotations and there is no xml file for AOP configuration?
1

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

3 Comments

I disagree. Aspects are arguably a more elegant way to achieving the same thing.
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.
interceptors are terrible, in general. who care's about URIs? i want to annotate exactly which controllers should execute which pieces of logic. annotations with aspects is the only way to do this.
0
@Aspect @Component public class HttpTraceAspect { // step1: interceptor all method in given package and sub packages @Pointcut("within(com.abc.xxx.admin.v2.controller..*)") public void pointCut1() { } @Pointcut("within(com.abc.xxx.admin.v1.old.controller..*)") public void pointCut2() { } @Around("pointCut1() || pointCut2()") public Object intercept(ProceedingJoinPoint pjp) throws Throwable { MethodSignature methodSignature = (MethodSignature) pjp.getSignature(); Method method = methodSignature.getMethod(); HttpServletRequest request = HttpUtils.getHttpRequest(); // step2: only intercept http method entry if (request == null || !isHttpMethodEntry(method)) { return pjp.proceed(); } Object result = null; try { result = pjp.proceed(); log.info("http trace, reqParams->{}, uri->{}, user->{}, response->{}", toJSONString(pjp.getArgs()), request.getRequestURI(), getLoginUsername(), toJSONString(result)); return result; } catch (Throwable t) { log.warn("http error, reqParams->{}, uri->{}, user->{}", toJSONString(pjp.getArgs()), request.getRequestURI(), getLoginUsername(), t); throw t; } } private boolean isHttpMethodEntry(Method method) { if (method.getDeclaredAnnotations() != null) { for (Annotation annotation : method.getDeclaredAnnotations()) { if (annotation.annotationType().getName().startsWith("org.springframework.web.bind.annotation.")) { return true; } } } return false; } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.