2017-11-10 10 views
0

우리의 프로젝트에서는 Grails/Spring 부트의 임베디드 tomcat 컨테이너에 다른 기존 war 파일을 추가 할 때 우리의 기본 Hibernate 세션이 손실 된 것으로 보입니다.임베디드 톰캣에 전쟁을 추가 할 때 현재 스레드에 대한 세션이 없음

war 파일을 추가하기 위해 성명을 언급하자마자 모든 것이 예상대로 작동합니다. 애플리케이션을 프로덕션 환경에 배포 할 때이 문제는 존재하지 않으며 어쨌든 개발시 추가하려고하는 war 파일도 프로덕션 환경에서 시작됩니다.

우리는 Grails 3.3.1을 사용하고 있습니다. 이것은 Spring 부트를 기반으로 작성되었으며 Applications.groovy 파일을 통해 기존의 war 파일을 emnbedded tomcat에이 방법으로 추가합니다.

위가 설정되어
class Application extends GrailsAutoConfiguration implements EnvironmentAware { 
static void main(String[] args) { 
    GrailsApp.run(Application, args) 
} 

@Bean 
EmbeddedServletContainerFactory servletContainerFactory() { 
    return new TomcatEmbeddedServletContainerFactory() { 

     @Override 
     protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) { 
       try { 
        // Ensure that the folder exists 
        tomcat.getHost().getAppBaseFile().mkdir() 
        String projektrod = System.getProperty('user.dir') 
        // Add external Orbeon war file 
        Context context = tomcat.addWebapp("/blanketdesigner/orbeon", "${projektrod}\\..\\blanket-orbeon-plugin\\orbeon\\orbeon.war") 
        context.setParentClassLoader(getClass().getClassLoader()) 
       } catch (ServletException ex) { 
        throw new IllegalStateException("Failed to add webapp", ex) 
       } 
       return super.getTomcatEmbeddedServletContainer(tomcat) 
     } 
    } 
} 

, 응용 프로그램, 외부 war 파일 모두 시작, 예상대로 작동하지만, 우리는 도메인에 그렇게 .withTransaction, .withNewTransaction, .withNewSession 또는 뭔가를 호출해야한다 사물.

@Transactional 주석이 붙은 서비스에서도 마찬가지입니다. 우리가이 일을하지 않을 경우, 우리는 다음과 같은 예외가 발생합니다

No Session found for current thread. Stacktrace follows: 
java.lang.reflect.InvocationTargetException: null 
    at org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:211) 
    at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:188) 
    at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90) 
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) 
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) 
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) 
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) 
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) 
    at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55) 
    at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77) 
    at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at java.lang.Thread.run(Thread.java:745) 
Caused by: org.hibernate.HibernateException: No Session found for current thread 
    at org.grails.orm.hibernate.GrailsSessionContext.currentSession(GrailsSessionContext.java:117) 
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:688) 
    at org.grails.orm.hibernate.HibernateSession.createQuery(HibernateSession.java:177) 
    at org.grails.orm.hibernate.HibernateSession.createQuery(HibernateSession.java:170) 
    at org.grails.datastore.gorm.finders.FindAllByFinder.buildQuery(FindAllByFinder.java:63) 

을 우리가 예상 한대로

tomcat.addWebapp("....") 

모든 작동 전쟁 파일을 추가하는 행을 제거하고, 경우에 우리는 도메인 객체로 작업 할 수 있습니다 .with와 전화 할 필요없이 ...

앞에서 언급했듯이이 문제는 임베디드 톰캣 서버와 war 파일을 추가하는 기능에 문제가있는 것으로 보입니다.

코드 전체에서 .with ...를 호출하지 않으려합니다. 올바른 해결책이 아니기 때문입니다.

우리는 war 파일을 개발시에 임베디드 톰캣에 추가해야하는 이유는 우리의 주 응용 프로그램이 모든 기능이 작동하는 다른 전쟁에 의존하기 때문입니다. 프로덕션 서버에서는 별도의 웹 응용 프로그램으로 실행됩니다.

우리는 환경이 개발 될 때 기본 동면 방식 세션을 첨부하기위한 수정 사항을 가지고 살 수 있지만 이것을 수행하는 방법을 파악할 수는 없습니다. 이

if(grails.util.Environment.current == grails.util.Environment.DEVELOPMENT) { 
    // Then bind new default session to current thread 
} 

같은의

생각 재생이 용이해야한다.

더 디버깅에 의해,

감사

+0

디버깅을 시도 했습니까? Grails가 데이터베이스에 세션을 가져 오지 못했다고 나에게 보인다. –

+0

안녕하세요, 웨슬리, 당신이 옳다고 생각합니다. 내가 (org.hibernate.SessionFactory로 grails.util.Holders.applicationContext.getBean ("sessionFactory에")) .currentSession 이 나에게 같은 예외 제공 실행 시도 : 없음 세션은 현재 스레드에 대한 발견을 당신에게 수 좀 더 구체적으로 어떻게 디버깅 할 수 있을까요? 아니면 내가 올바른 방향으로 나를 이끌어 갈 수 있는지 찾아 볼 수 있을까? 감사합니다. –

답변

1

@WesleyDeKeirsmaeker 어떤 도움이나 제안을 주셔서 감사합니다, 나는 호출하여 외부 war 파일을 추가 할 때 전체 봄 부트 환경이 "두 번 시작되었는지 알게되었습니다. addWebapp (...) ".

이 다음 두 번 설정 방법 :이 다른 스레드에 의해 설정되어 있기 때문에

public GrailsSessionContext(SessionFactoryImplementor sessionFactory) { 
    this.sessionFactory = sessionFactory; 
} 

Grails는이 getCurrentSession()를 호출, 위에서 언급 한 문제를 일으키는 것 같습니다.

도메인 개체로 작업 할 때 TransactionSynchronizationManager.getResource (sessionFactory); null를 돌려줍니다.

public Session currentSession() throws HibernateException { 
    Object value = TransactionSynchronizationManager.getResource(sessionFactory); 
    if (value instanceof Session) { 
     return (Session) value; 
    } 

    if (value instanceof SessionHolder) { 
     SessionHolder sessionHolder = (SessionHolder) value; 
     Session session = sessionHolder.getSession(); 
     if (TransactionSynchronizationManager.isSynchronizationActive() && !sessionHolder.isSynchronizedWithTransaction()) { 
      TransactionSynchronizationManager.registerSynchronization(createSpringSessionSynchronization(sessionHolder)); 
      sessionHolder.setSynchronizedWithTransaction(true); 
      // Switch to FlushMode.AUTO, as we have to assume a thread-bound Session 
      // with FlushMode.MANUAL, which needs to allow flushing within the transaction. 
      FlushMode flushMode = HibernateVersionSupport.getFlushMode(session); 
      if (flushMode.equals(FlushMode.MANUAL) && !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { 
       HibernateVersionSupport.setFlushMode(session, FlushMode.AUTO); 
       sessionHolder.setPreviousFlushMode(flushMode); 
      } 
     } 
     return session; 
    } 

    if (jtaSessionContext != null) { 
     Session session = jtaSessionContext.currentSession(); 
     if (TransactionSynchronizationManager.isSynchronizationActive()) { 
      TransactionSynchronizationManager.registerSynchronization(createSpringFlushSynchronization(session)); 
     } 
     return session; 
    } 

    if (allowCreate) { 
     // be consistent with older HibernateTemplate behavior 
     return createSession(value); 
    } 

    throw new HibernateException("No Session found for current thread"); 
} 

내 외부 전쟁 파일을 시작하는 하위 컨테이너에 args를 전달하는 방법이 있다면 생각 중입니다. 인수를 전달할 수 있다면, 시작할 때 데이터베이스 관련 빈/자동 구성을 사용하지 못하게 할 수 있으며 GrailsSessionContext가 두 번 호출되지 않습니다.

여기서 발견 된 인수는 Disable related auto configurations입니다.

자식 컨테이너에 인수를 전달하는 방법이 있습니까? 나는 어떤 것을 연결하는 방법을 찾고있다.