Spring AOP Advice on Annotated Controllers
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.
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.
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.
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
@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;
}
}
精彩评论