【问题标题】:Spring AOP Advice on Annotated ControllersSpring AOP 关于注解控制器的建议
【发布时间】:2011-03-19 14:46:34
【问题描述】:

我正在尝试使用 AOP 在带注释的控制器之后进行一些处理。一切都在运行,没有错误,但建议没有被执行。

这是控制器代码:

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

以及应用程序配置中的设置

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

以及实际的建议

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!");
    }
}

甚至可以对带注释的控制器提出建议吗?我正在使用 Spring 2.5。

【问题讨论】:

  • 我一直无法让它工作,不幸的是,我已经没有时间去工作了。现在我不得不坚持只复制代码。
  • 您需要在&lt;aop:aspectj-autoproxy/&gt; 中包含您的testAdvisor bean,如下所示:&lt;aop:include name="testAdvisor"/&gt;

标签: java spring spring-mvc aop aspectj


【解决方案1】:

可以对带注释的控制器提出建议。

我假设您想在执行带有 @Controller 注释的类中的所有方法后提出建议。

这是一个例子:

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..");
    }
}

如果你想使用带有 AspectJ 语法的 Spring AOP,你还需要一个这样的配置文件:

<?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>

注意:使用 Spring AOP,Spring 容器只会编织 Spring bean。如果 @Controller 对象不是 Spring bean,则必须使用 AspectJ weaving。

【讨论】:

  • 如何判断 @Controller 是否是 bean?我知道它通过@Autowired 正确接收依赖项,所以我认为它是一个 bean,但我仍然无法让方面执行。
  • 如果自动装配有效,并且除了 Spring 之外没有其他 IOC 容器,那么它就是 Spring bean。
  • 我的其他组件在方面工作得很好,但控制器却没有运气。在同一个方面类中,我定义了控制器切入点和服务切入点。服务切入点有效,但控制器无效。是否有任何线索说明为什么会发生这种情况?
【解决方案2】:

我遇到了同样的问题,即针对 Repository 的建议有效,但针对 Controller 的建议却没有。最后我找到了解决方案。简而言之,您需要确保您的 AOP 定义是在 Servlet 上下文中加载的,而不是在不同的上下文中。

就我而言,我的 Spring AOP 定义在 tools-config.xml 中定义。从这里移走后

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

到这里,

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

Controller 的建议有效。

【讨论】:

  • 如果一切都是通过注解并且没有用于AOP配置的xml文件怎么办?
【解决方案3】:

对于 MVC 控制器,完成您尝试做的事情的首选方法是使用拦截器。见http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-handlermapping-interceptor

【讨论】:

  • 我不同意。方面可以说是实现相同目标的一种更优雅的方式。
  • 我的一般规则是当你想拦截某些网络请求时使用拦截器。当您想要拦截普通 spring bean 上的方法时,请使用 Aspects。由于问题与拦截控制器(映射到 Web 请求)有关,因此使用拦截器更合适。
  • 拦截器通常很糟糕。谁在乎 URI?我想准确注释哪些控制器应该执行哪些逻辑。带有方面的注释是这样做的唯一方法。
猜你喜欢
  • 2018-07-26
  • 1970-01-01
  • 1970-01-01
  • 2017-03-21
  • 2015-01-12
  • 1970-01-01
  • 2015-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多