【问题标题】:Using the grails Quartz plugin without Hibernate在没有 Hibernate 的情况下使用 grails Quartz 插件
【发布时间】:2011-01-18 06:31:55
【问题描述】:

我正在开发一个后端 Grails 应用程序,该应用程序定期从 RESTful 服务中提取信息。为此,我安装了 Grails Quartz 插件。

grails install-plugin quartz

然后我使用

创建了一个工作
grails create-job My

它生成了一个我用 cron 触发器配置的 MyJob 文件

static triggers = {
    cron name: 'myTrigger', cronExpression: '0 0 * * * ?' // hourly
}

在开发环境中本地运行应用程序可以正常工作,但是一旦我尝试构建测试或生产战争,当触发器运行时,我会收到以下异常。

2010-02-18, 00:04:32 ERROR org.codehaus.groovy.grails.web.context.GrailsContextLoader - Error occurred shutting down plug-in manager: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'quartzScheduler':
Cannot resolve reference to bean 'sessionBinderListener' while setting bean property 'jobListeners' with key [0]; nested
 exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionBinderListener': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'sessionFactory': Cannot resolve reference to bean 'hibernateProperties' while setting bean property 'hibernateProperties'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating
bean with name 'hibernateProperties': Cannot resolve reference to bean 'dialectDetector' while setting bean property 'properties' with key [hibernate.dialect]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dialectDetector': Invocation of init method failed; nested exception is org.springframework.jdbc.support.MetaDataAccessException: Error while extracting DatabaseMetaData; nested exception is java.sql.SQLException : Access is denied: Session is closed

由于我不需要数据库,所以我尝试删除 Hibernate 插件as suggested, 但是一旦删除了 Hibernate 插件,我就会遇到编译问题:

Running script C:\Downloads\grails-1.2.1\scripts\RunApp.groovy  
Environment set to development  
[groovyc] Compiling 18 source files to C:\Projects\myapp\target\classes  
[groovyc] org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, Compile error during compilation with javac.  
[groovyc] ...\myapp\plugins\quartz-0.4.1\src\java\org\codehaus\groovy\grails\plugins\quartz\listeners\SessionBinderJobListener.java:19: package org.hibernate does not exist  
[groovyc] import org.hibernate.FlushMode;  
...

有没有办法在没有 Hibernate 插件的情况下使用 Quartz 插件?
如果没有,最好的办法是配置一个内存数据库供 Quartz 使用吗?
(我不关心这些数据的持久性。)

【问题讨论】:

    标签: hibernate grails plugins groovy quartz-scheduler


    【解决方案1】:

    我得到了 Quartz 插件 (0.4.2),在没有 Hibernate 插件和编辑 Quartz 插件的情况下工作得相当干净。

    在 BuildConfig.groovy 中添加对 Hibernate 的运行时依赖,只是为了拉入 jars:

    dependencies {
        ...
        // the Quartz plugin depends on some Hibernate classes being available
        runtime('org.hibernate:hibernate-core:3.6.7.Final') {
            exclude group:'commons-logging', name:'commons-logging'
            exclude group:'commons-collections', name:'commons-collections'
            exclude group:'org.slf4j', name:'slf4j-api'
            exclude group:'xml-apis', name:'xml-apis'
            exclude group:'dom4j', name:'dom4j'
            exclude group:'antlr', name:'antlr'
        }
    }
    

    Quartz 仍然安装一个 SessionBinderJobListener 来将 Hibernate 会话绑定到作业线程。像这样创建一个 NOP 会话绑定器:

    import org.quartz.listeners.JobListenerSupport
    
    class NopSessionBinderJobListener extends JobListenerSupport {
        String getName() { return "sessionBinderListener" }
    }
    

    并在 resources.groovy 中创建一个 Spring bean:

    beans = {
        ...
        // dummy session binder to work around issue with Quartz requiring Hibernate
        sessionBinderListener(NopSessionBinderJobListener) { }
    }
    

    【讨论】:

      【解决方案2】:

      好像有代码依赖,在quartz-0.4.1\src\java\org\codehaus\groovy\grails\plugins\quartz\listeners\SessionBinderJobListener.java:1

      然后你不能在没有休眠类的情况下编译quartz plugin。也许您可以将它们放在lib 文件夹中?或者如果你使用 maven/gradle 则将其添加为 compile 依赖项

      【讨论】:

      • 感谢 splix,如果我要捆绑 Hibernate jar,那么我不妨保留 Hibernate 插件。我已经设法通过确保所有数据库都在内存中来使其正常工作,请参阅我的答案。
      【解决方案3】:

      我已经设法通过安装 Hibernate 插件并配置内存数据库来完成这项工作。在 DataSource.groovy 中

      ...
      environments {
        development {
          dataSource {
            dbCreate = "create-drop" // one of 'create', 'create-drop','update'
            url = "jdbc:hsqldb:mem:myDevDb"
          }
        }
        test {
          dataSource {
            dbCreate = "create-drop"
            url = "jdbc:hsqldb:mem:myTestDb"
          }
        }
        production {
          dataSource {
            dbCreate = "create-drop"
            url = "jdbc:hsqldb:mem:myProdDb;shutdown=true"
          }
        }
      }
      ...
      

      更改是在测试和生产数据库上设置“create-drop”,并将生产数据库设置为“mem”而不是“file”。

      【讨论】:

        【解决方案4】:

        所以,

        这是我想出的解决方案(请注意,我不喜欢一开始就保持休眠状态)。该解决方案使用 Grails 1.2.1 和 Quartz 插件 0.4.1 进行了测试,并以常规方式清除了休眠 (grails uninstall-plugin hibernate)。保存在内存数据库中也不是我能找到的最佳选择。

        创建或编辑scripts/_Events.groovy

        eventCompileStart = {bindings->
         println "Compile Start: Plugin dir is ${grailsSettings.projectPluginsDir}"
         // Kill standard listener which actually wants to use hibernate (to restore hibernate session)!
         Ant.delete(file:"${grailsSettings.projectPluginsDir}/quartz-0.4.1/src/java/org/codehaus/groovy/grails/plugins/quartz/listeners/SessionBinderJobListener.java")
        }
        

        现在为了补偿文件删除(它是从 GrailsQuartzPlugin.groovy 的某个地方引用的,我们需要在项目中创建该类的“安全”版本,也就是 src/java/org/codehaus/groovy/grails/plugins/quartz/listeners/SessionBinderJobListener.java

        这就是我放在那里的内容,保持所有原始版权和作者不变 - 但没有休眠状态(让它 R.I.P.):

        
        /* Copyright 2006-2008 the original author or authors.
         * 
         * Licensed under the Apache License, Version 2.0 (the "License");
         * you may not use this file except in compliance with the License.
         * You may obtain a copy of the License at
         * 
         *      http://www.apache.org/licenses/LICENSE-2.0
         * 
         * Unless required by applicable law or agreed to in writing, software
         * distributed under the License is distributed on an "AS IS" BASIS,
         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         * See the License for the specific language governing permissions and
         * limitations under the License.
         */
        package org.codehaus.groovy.grails.plugins.quartz.listeners;
        
        import org.apache.commons.logging.Log;
        import org.apache.commons.logging.LogFactory;
        import org.quartz.JobExecutionContext;
        import org.quartz.JobExecutionException;
        import org.quartz.listeners.JobListenerSupport;
        
        /**
         * JobListener implementation which binds Hibernate Session to thread before
         * execution of job and flushes it after job execution.
         * 
         * @author Sergey Nebolsin (nebolsin@gmail.com)
         * 
         * @since 0.2
         */
        public class SessionBinderJobListener extends JobListenerSupport
        {
          private static final transient Log LOG = LogFactory.getLog(SessionBinderJobListener.class);
        
          public static final String NAME = "sessionBinderListener";
        
          public String getName()
          {
            return NAME;
          }
        
          @Override
          public void jobToBeExecuted(final JobExecutionContext context)
          {
          }
        
          @Override
          public void jobWasExecuted(final JobExecutionContext context, final JobExecutionException exception)
          {
          }
        
        }
        

        警告:解决方案是“hack”,它会覆盖插件中的一些文件。要移除 hack:

        • 确保您卸载了quartz插件,

        • 转到${grailsSettings.projectPluginsDir}(在每次运行grails compile 和更高级别的脚本(包括grails war)期间,黑客会打印位置)并确保没有留下任何工件。

        • 删除两个 hack 工件

        • 重新安装新的quartz插件。

        【讨论】:

        • 嘿 Vadim,看起来要让 Grails 在没有 Hibernate 的情况下运行 Quartz 需要进行很多脆弱的黑客攻击。感谢分享,尤其是破解的展开!对我来说,运行内存数据库是一个更简单的解决方案 :)
        【解决方案5】:

        对于 Quartz grails 插件的 1.0.RC7 版本,我不得不添加一些额外的步骤。它基于@DavidTinker 的回复。

        在 resources.groovy 中,我必须添加一个 Nop 会话工厂和一个 Nop Session(确保它正在实现 org.hibernate.classic.Session)

        beans = {
           // dummy session binder to work around issue with Quartz requiring Hibernate
           sessionBinderListener(NopSessionBinderJobListener) { }
           sessionFactory( NopSessionFactory) {}
        }
        

        NopSessionFactory.groovy:

        class NopSessionFactory implements SessionFactory
        {
        
            @Override
            Session openSession() throws HibernateException {
               return new NopSession()
            }
         // Implement all of the methods required by this interface and return a NopSession for any method that returns a session
        }  
        

        而且,就我而言,我需要为注入到我的 Quartz 作业中的任何服务添加 No-op Transaction 管理器,或者将服务标记为非事务性(我选择这样做)。

        class FooService {     
           static transactional = false
        

        我还必须排除休眠传递依赖项,但由于我使用 gradle 构建项目,它看起来像这样:

        // Needed by quartz
        runtime('org.hibernate:hibernate-core:3.6.10.Final') {
            exclude group:'commons-logging', module:'commons-logging'
            exclude group:'commons-collections', module:'commons-collections'
            exclude group:'org.slf4j', module:'slf4j-api'
            exclude group:'xml-apis', module:'xml-apis'
            exclude group:'dom4j', module:'dom4j'
            exclude group:'antlr', module:'antlr'
        }
        

        【讨论】:

          猜你喜欢
          • 2012-02-21
          • 2023-03-10
          • 1970-01-01
          • 2011-03-06
          • 1970-01-01
          • 2010-11-05
          • 2014-05-11
          • 2022-11-07
          • 2012-09-30
          相关资源
          最近更新 更多