当前位置: 首页 > 知识库问答 >
问题:

将war添加到嵌入式tomcat时,当前线程没有会话

鞠通
2023-03-14

在我们的项目中,当将另一个现有war文件添加到Grails/Spring Boot中的嵌入式tomcat容器时,我们的默认Hibernate会话似乎丢失了。

我们使用的是在Spring boot上构建的Grails3.3.1,并通过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)

如果我们删除添加war文件的行

 tomcat.addWebapp("....")

所有的工作都是预期的,我们可以使用域对象而不需要调用...

如前所述,这个问题似乎是嵌入式tomcat服务器和添加war文件的函数的问题。

我们不想打电话...因为这些都不是正确的解决方案。

为什么在开发时要将war文件添加到嵌入式tomcat中,是因为我们的主应用程序的所有功能都依赖于其他war来工作。在生产服务器上,它也作为一个单独的Web应用程序运行。

想着这样的事情

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

应该很容易复制。

如有任何帮助或建议,我将不胜感激

谢谢

共有1个答案

阙辰龙
2023-03-14

@wesleydekeirsmaeker,通过进一步调试,我发现整个Spring Boot环境启动了两次,当我通过调用“.addwebapp(...)”添加外部war文件时。

这意味着以下内容设置了两次:

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

当Grails调用getCurrentSession()时,上面的操作似乎会导致问题,因为它是由另一个线程设置的。

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

在此处找到参数禁用相关的自动配置。

有没有一种方法可以将参数传递给子容器?我在找一种方法。

 类似资料:
  • 我已经搜索了这个问题,但我没有找到任何关于这个案例的东西。我发现了很多“如何将Spring Boot WAR部署到Tomcat”,但是没有关于用Spring Boot包装现有的Tomcat WAR的内容。 我正在尝试用Spring Boot“包装器”包装一个现有的WAR,这样就不必重新配置现有的代码库。这个解决方案不起作用,因为它依赖于在绝对位置可用的WAR,而我们正试图将“应用程序”WAR打包在

  • 我想用Maven创建一个不嵌入tomcat的war文件。这里是我的pom的相关部分 如果我运行mvn包,我会得到一个war,其中tomcat*.jar位于provided-lib文件夹中,但仍然位于lib-folder中。我读了build-tool-plugins-maven-packaging,但找不到有什么问题。 我知道一个主要的想法是将它作为一个应用程序来运行,无论我们的客户想要如何将它部署

  • 问题内容: Spring Boot的嵌入式tomcat非常便于开发和部署。 但是,如果应该添加另一个(第三方)WAR文件(例如GeoServer)怎么办? 也许以下是正常过程: 安装普通的Tomcat服务器。 将Spring Boot应用程序构建为WAR文件,并将其添加到Tomcat的webapps文件夹中。 还将另一个(第三方)WAR文件添加到webapps文件夹。 但是,如果可以进行以下配置,

  • 基本上,我想在Tomcat 8嵌入式中运行一些Rest类。我不确定如何将它们添加到我正在创建的tomcat嵌入式实例中。所以这就是我所做的。这里只有泽西班: 下面是我创建Tomcat的类: 正如你看到的,带问号的部分给我制造麻烦。还有一个lats问题,这就是我应该添加这些类以在服务器上运行的方式,对吗? 更新我添加了Michal Gajdos建议的行,但在启动时我得到: 线程“main”java中

  • Spring Boot的嵌入式tomcat对于开发和部署都非常方便。 但是,如果应该添加另一个(第三方)WAR文件(例如,GeoServer)怎么办? 安装普通Tomcat服务器。 将Spring Boot应用程序构建为WAR文件,并将其添加到Tomcat的webapps文件夹中。 还要向webapps文件夹中添加另一个(第三方)WAR文件。 但如果有以下配置可能就好了。 将Spring Boot

  • 我试图在运行时向tomcat添加一个端口。有办法做到这一点吗?或者有没有办法监听所有端口?我使用的是spring,我希望用户能够添加一个APIendpoint调用,以添加一个新的端口来侦听。 我知道您可以在配置文件中添加其他端口,但我不知道我需要添加哪些端口。