【发布时间】: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 类,那么为什么它与我的切入点匹配?因为HandlerInterceptorAdapter 在servlet.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;。我将在我的帖子中包含整个堆栈跟踪。