1

函数 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: No Session found for current thread”异常(getDefects() 虽然是事务性的)。

当我用“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)
4

1 回答 1

1

在 Groovy 类中,属性访问

service.defects

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

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实现执行ImportLogsService通常的默认行为并调用自己的getIncidents方法

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)

请注意,这是目标服务对象的内部,因此不会再次通过 Spring 事务代理层。因此,即使getIncidents()被标记为@Transactional事务拦截器也不会被调用。最后getIncidents()调用到 DAO 层

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)

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

如果您service.getIncidents()首先调用,那么该方法(标记为事务性的)将成为 Spring 代理的第一个入口点,并且事务上下文将被正确设置。

尝试将整个ImportLogsService 注释为@Transactional,而不仅仅是单个方法。这应该会导致事务拦截器getProperty以及getIncidents().

于 2013-07-22T15:51:14.910 回答