2017-11-10 12 views
0

プロジェクトでは、既存のwarファイルを追加するときに、デフォルトのHibernateセッションがGrails/Springブートの埋め込みTomcatコンテナに失われているようです。埋め込みのTomcatにwarを追加するときに現在のスレッドのセッションがありません

私たちがステートメントにコメントするとすぐに、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を呼び出す必要はありません。

前述したように、この問題は組み込みのTomcatサーバーとwarファイルを追加する機能の問題です。

これは適切な解決策ではないため、コード全体で.with ...を呼び出すことは望ましくありません。

私たちの主なアプリケーションは、すべての機能が動作するための他の戦争に依存しているため、warファイルを埋め込みのTomcatに追加する必要があります。プロダクションサーバー上では別のWebアプリケーションとして実行されています。

環境が開発されているときに、デフォルトの休止状態セッションを添付するための修正プログラムを用意していますが、これを行う方法はわかりません。

再現が容易であるべき

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

このような何かを考えます。

は、任意のヘルプや提案

おかげ

+0

デバッグを試しましたか? Grailsがあなたのデータベースへのセッションを取得できないと私に思えます。 –

+0

こんにちはウェズリー、 私はあなたが正しいと思います。 セッションが現在のスレッドが見つかり は、次のことができます。私は.currentSession これは私に同じ例外を与える (org.hibernate.SessionFactoryとしてgrails.util.Holders.applicationContext.getBean(「SessionFactoryの」)) を実行しようとしていますより具体的にどのように私はこれをデバッグできますか?それとも、正しい方向に私を導くためにあなたが見つけようとしているものがありますか? ありがとうございます。 –

答えて

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"); 
} 

外部のwarファイルを起動する子コンテナにargsを渡す方法があると思います。引数を渡すことができれば、起動時にデータベース関連のBean /自動設定を無効にでき、GrailsS​​essionContextが2回呼び出されることはありません。

ここに引数があります。Disable related auto configurations

子コンテナに引数を渡す方法はありますか?私はフックする方法を探しています。

関連する問題