调用方法之间的常规差异

时间:2013-07-22 12:17:32

标签: spring hibernate groovy

函数service.defects和service.getDefects()

的调用之间在groovy中有什么区别
@RequestMapping("/test1")
 ModelAndView getTest1() {
    ModelAndView mav = new ModelAndView()
    mav.viewName = "test"
    List<Defect> defects = service.defects
    mav
}


 @RequestMapping("/test2")
  ModelAndView getTest2() {
     ModelAndView mav = new ModelAndView()
     mav.viewName = "test"
     List<Defect> defects = service.getDefects()
     mav
 }

我在这个问题上挣扎了很长一段时间,虽然我觉得这些电话都是一样的,但事实并非如此。在我的场景中,service.defects的调用导致了“org.hibernate.HibernateException:找不到当前线程的会话”异常(getDefects()虽然是Transactional)。

当我用“service.defects”调用方法时,有人可以解释一下我发生了什么吗

这是我得到的堆栈跟踪:

org.hibernate.HibernateException: No Session found for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:883)
    at org.hibernate.SessionFactory$getCurrentSession.call(Unknown Source)
    at com.test.dao.LogDBDao.getExceptionLogFileEntry(LogDBDao.groovy:35)
    at com.test.dao.ILogDBDao$getExceptionLogFileEntry.call(Unknown Source)
    at com.test.service.ImportLogsService.getIncidents(ImportLogsService.groovy:34)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1580)
    at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3308)
    at com.test.service.ImportLogsService.getProperty(ImportLogsService.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)
    at com.test.service.$Proxy27.getProperty(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:227)
    at com.test.controller.IncidentController.getIncidents(IncidentController.groovy:22)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

1 个答案:

答案 0 :(得分:1)

在Groovy类中,属性访问

service.defects

成为对service.getProperty("defects")的调用,其默认实现最终将委托给service.getDefects()。因此,从IncidentController调用getProperty("incidents")调用service对象(这是一个Spring AOP代理)来处理堆栈跟踪。

at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)
at com.test.service.$Proxy27.getProperty(Unknown Source)
at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:227)
at com.test.controller.IncidentController.getIncidents(IncidentController.groovy:22)

该方法标记为事务性,因此Spring在调用基础对象上的方法之前无需设置事务上下文

at com.test.service.ImportLogsService.getProperty(ImportLogsService.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)

现在getProperty的{​​{1}}实现执行常规默认行为并调用自己的ImportLogsService方法

getIncidents

请注意,这是目标服务对象的内部,因此再次通过Spring事务代理层。因此,即使at com.test.service.ImportLogsService.getIncidents(ImportLogsService.groovy:34) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233) at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1580) at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3308) 被标记为getIncidents(),也不会调用事务拦截器。最后@Transactional调用DAO图层

getIncidents()

失败,因为没有设置上下文。

如果您首先调用at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97) at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:883) at org.hibernate.SessionFactory$getCurrentSession.call(Unknown Source) at com.test.dao.LogDBDao.getExceptionLogFileEntry(LogDBDao.groovy:35) at com.test.dao.ILogDBDao$getExceptionLogFileEntry.call(Unknown Source) ,那么该方法(标记为事务性)将是进入Spring代理的第一个点,并且将正确设置事务上下文。

尝试将整个service.getIncidents() 注释为ImportLogsService,而不仅仅是单个方法。这会导致交易拦截器在@Transactional以及getProperty上触发。