【问题标题】:Around advice behaving strange周围的建议表现得很奇怪
【发布时间】:2016-11-18 13:20:49
【问题描述】:

我在 Spring 中使用基于 XML 的 AOP,并且我有以下切入点:

<aop:aspect id=".." ref="..">
    <aop:pointcut id="interceptController" expression="execution(ModelAndView org.springframework.web.servlet.mvc.Controller+.handleRequest(HttpServletRequest, ..))" />
    <aop:around method="myAroundAdvice" pointcut-ref="interceptController" />
</aop:aspect>

我的建议如下:

public Object myAroundAdvice(ProceedingJoinPoint jp) throws Throwable {
    if (someCondition) {
        Object test = jp.proceed();
        return test;
    }
    else {
        return new ModelAndView("redirect:index.htm");
    }
}

上面代码的问题是,如果我们进入 if 表达式的 true 子句,一切正常,但是,如果我们进入 else 子句,程序就会崩溃并出现错误:

SEVERE: Servlet.service() for servlet ... threw exception
java.lang.ClassCastException: org.springframework.web.servlet.ModelAndView cannot be cast to java.lang.Boolean

所以我在Object test = jp.proceed 行上放了一个断点,我注意到jp.proceed(); 返回布尔值true。因此,在 else 子句中,当我返回一个新的 ModelAndView 时,它会崩溃,因为它希望从建议中返回一个布尔值..

为什么这个建议会返回一个布尔值?在切入点表达式中,我指定我匹配的方法执行的返回类型是ModelAndView,因此,proceed() 以及我的建议应该返回一个ModelAndView..

我在这里错过了什么?


更新: 正如所指出的,我尝试打印连接点。因此我打印了连接点及其目标:

System.out.println("jp is : " + jp.toString());
System.out.println("target is : " + jp.getTarget().toString());

访问网页时会打印以下内容:

jp is : org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint: execution(preHandle)
target is : my.packages.etc.LoginInterceptor@5b181df3

jp is : org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint: execution(postHandle)
target is : my.packages.etc.LoginInterceptor@5b181df3

jp is : org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint: execution(afterCompletion)
target is : my.packages.etc.LoginInterceptor@5b181df3

注意LoginInterceptor 扩展了HandlerInterceptorAdapter 类,那么为什么它与我的切入点匹配?因为HandlerInterceptorAdapterservlet.handler 中,而我在servlet.mvc.Controller+.handleRequest 上匹配。


整个轨迹:

18-nov-2016 14:52:26 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet ... threw exception
java.lang.ClassCastException: org.springframework.web.servlet.ModelAndView cannot be cast to java.lang.Boolean
    at com.sun.proxy.$Proxy32.preHandle(Unknown Source)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:865)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:112)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:612)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:503)
    at java.lang.Thread.run(Thread.java:695)

【问题讨论】:

  • 你有没有检查到底是哪个方法被拦截了? ClassCastException 到底发生在哪里?
  • @PredragMaric 它匹配控制器的handleRequest 方法(这是一个AbstractController)。因此,我的控制器扩展了AbstractController 并实现了handleRequestInternal 方法。因此,我匹配handleRequest 方法,如果我调用proceed(),它将调用我的handleRequestInternal 方法,否则我想返回一个新的ModelAndView 以重定向用户。关于异常,它被抛出return test;。我将在我的帖子中包含整个堆栈跟踪。

标签: java spring aop


【解决方案1】:

我认为你的切入点不会拦截你认为它所做的事情。由于某种原因,它似乎拦截了返回布尔值的方法。尝试在控制台打印jp,看看你拦截了哪个方法。

这样的切入点看起来基本没问题,但有一件事让我印象深刻:ModelAndView 不是一个完全限定的类名。也许你想改变它。

【讨论】:

  • 你说得对,我打印了jp.getTarget().toString(),它在我的项目中打印了一些类LoginInterceptor。似乎它拦截了LoginInterceptor 类的preHandle 方法,该方法确实返回了一个布尔值。但是,这个 LoginInterceptor 类扩展了 org.springframework.web.servlet.handler.HandlerInterceptorAdapter ,所以我不明白为什么这个方法被拦截,因为我的切入点应该只从 servlet.mvc.Controller+ 类中拦截 HandleRequest,而这个方法在 servlet.handler.. . 请注意,我将ModelAndView 更改为其完全限定名称。
  • 我假设有另一个切入点与相同的建议方法相关联,因为您在问题中显示的切入点不会拦截诸如preHandlepostHandleafterCompletion 之类的方法。请参考方法myAroundAdvice检查您的方面代码以及其他地方的配置。
  • 对,我也是这么想的,但是原来的项目没有集成AOP。我的工作是集成 AOP 来做各种事情。我注释掉了所有其他切入点,因此这确实是唯一的切入点,但是问题仍然存在。为了 100% 确定,我更改了建议的名称,并在我的 xml 文件中引用了该新名称,但是,相同的行为仍然存在,因此,我确信没有其他切入点意外指向相同的建议。这真的很奇怪。。我也给我的助教看了,他也被绊倒了。
  • 我设法解决了这个问题,使用基于注释的 AOP 而不是基于 XML 的 AOP,并重写了建议。感谢您的帮助!
猜你喜欢
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-12
  • 2012-11-11
  • 1970-01-01
  • 1970-01-01
  • 2015-09-14
相关资源
最近更新 更多