2

我已经在我的应用程序中成功使用了石英。基本上,我在 Jboss 内运行的 webapp1 中捆绑了石英。

但是我们在 jboss 中运行了另一个 webapp2,它也需要进行石英作业

现在我需要做的是让石英调度器作为某种服务在 jboss 中运行,并且两个 webapps 都应该能够在单个石英调度器上注册它们的作业。

下面是我对 webapp1 的相关 spring 配置,它一直工作到现在。

<bean id="qtzScheduler"
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="dataSource">
        <ref bean="jndiDataSource" />
    </property>
    <property name="applicationContextSchedulerContextKey">
        <value>applicationContext</value>
    </property>
    <property name="transactionManager">
        <ref bean="transactionManager" />
    </property>
    <property name="schedulerName" value="webapp1" />       
</bean>

<bean id="wrapperScheduler" class="uk.fa.quartz.schedule.ServiceScheduler">
    <property name="scheduler">
        <ref bean="qtzScheduler" />
    </property>
</bean>

<bean id="jndiDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName">
        <value>java:/FmManagerDS</value>
    </property>
</bean>

当我必须安排工作时,代码如下:

   WrapperScheduler scheduler = (WrapperScheduler) ctx.getBean("wrapperScheduler");
   scheduler.scheduleCronJob(job, jobName + "CronTrigger", WrapperScheduler.TRIGGER_GROUP, cronExpression);

现在我不想在 webapp2 中再次定义相同的调度程序,这将导致 2 个石英调度程序在 jboss 中运行。

有人知道怎么做吗?我在互联网上看到了一个示例,如下链接所示,我认为它正在做我想做的事。但我不明白如何使用我的 spring 源中定义的数据源将它与我的系统集成。如果有人可以分享配置或将我指向互联网上的正确资源,我将不胜感激。

4

2 回答 2

2

您参考的链接解释了如何访问JBoss 中内置的 Quartz 调度程序服务。我从来没有使用过这种方法,但基本上你让 JBoss 处理你的调度程序、数据源和它周围的一切。这使得在没有所有配置的情况下很容易利用作业调度 - 但不是很灵活,您的应用程序不再是独立的。

在您的情况下,我看到两个值得研究的选项:

集群 Quartz 调度器

将您的两个 Web 应用程序配置为在集群中运行。两个应用程序将共享相同的数据库并运行彼此定义的作业。由于以下几个原因,这可能不是您的选择:

  • 两个应用程序必须能够运行彼此定义的作业 - 例如,作业类必须在 CLASSPATH 上可用

  • 您仍然需要在两个应用程序中定义 Quartz 配置(尽管您可以轻松共享配置,例如通过将 XML 配置提取到单独的文件中)

  • 两个应用程序将维护单独的线程池

集群更适合在多台机器上运行的同构应用程序,而不是在单个节点上运行的异构应用程序。

远程调度程序

Quartz通过内置了对远程调度程序的支持。基本上,一个应用程序托管成熟的 Quartz 服务器,而另一个应用程序连接到该服务器。这对您来说似乎是一种更好的方法(我们称之为“主从”),因为只有一个应用程序管理调度程序,而另一个应用程序使用现有的。

见:RemoteScheduler

于 2012-08-13T18:14:26.790 回答
0

最后,我有时间为所有其他可能不得不使用 Quartz 作为在 jboss 中运行的服务的人写下这一切。但也可以尝试@Tomasz 在他的回答中提到的其他选项。

请注意,如果您尝试从绑定它的 JBoss 服务器外部检索它,您将得到一个空引用。如果您有这样的要求,您可能需要考虑使用 Quartz 的 RMI 支持。

1)首先确保你删除了 jboss/[profile]/lib 或 jboss 发行版附带的 quartz.rar 中任何现有的石英版本。

2)请将您的quartz.1.8.3.jar &quartz-jboss.1.8.jar 放入accesmanager/[profile]/lib

3)下面是quartz-service.xml的代码,需要放在jboss deploy文件夹中,它将启动Quartz调度程序:

    <server> 
     <mbean code="org.quartz.ee.jmx.jboss.QuartzService" 
     name="user:service=QuartzService,name=QuartzService">    
     <attribute name="JndiName">Quartz</attribute> 
     <attribute name="Properties">        
     org.quartz.scheduler.instanceName = BGSScheduler 
     org.quartz.scheduler.rmi.export = false 
     org.quartz.scheduler.rmi.proxy = false 
     org.quartz.scheduler.xaTransacted = false 
     org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool  
     org.quartz.threadPool.threadCount = 5 
     org.quartz.threadPool.threadPriority = 4 
     org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer = true
     org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
     org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT
     org.quartz.jobStore.driverDelegateClass =  org.quartz.impl.jdbcjobstore.StdJDBCDelegate
     org.quartz.jobStore.dataSource = QUARTZ
     org.quartz.dataSource.QUARTZ.jndiURL = java:FmManagerDS 
     org.quartz.jobStore.nonManagedTXDataSource = QUARTZ_NO_TX
     org.quartz.dataSource.QUARTZ_NO_TX.jndiURL = java:FmManagerDS
     </attribute>     
     <depends>jboss.jca:service=DataSourceBinding,name=FmManagerDS</depends>
     </mbean> 
     </server>

] 大多数事情都是不言自明的,或者您可以在Quartz Configuration获得更多详细信息 。关键是要注意,quartz 需要 2 个数据源。一个是容器管理的数据源 - 与 jboss *-ds.xml( java:FmManagerDS 在我的例子中)。如果您的 'org.quartz.jobStore.dataSource' 是 XA,则将 'org.quartz.jobStore.nonManagedTXDataSource' 设置为非 XA 数据源(对于同一数据库)。否则,您可以将它们设置为相同。

然后在spring applicationContext中,我必须得到quartz的句柄,这样我才能注入到wrapperScheduler。下面的代码

    <bean id="quartzScheduler" class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiName">
                <value>Quartz</value>
            </property>
    </bean>

<bean id="wrapperScheduler" class="k.fa.quartz.schedule.ServiceScheduler">
            <property name="scheduler">
                <ref bean="quartzScheduler" />
            </property>
    </bean>

然后我们可以使用以下方式安排作业

Timestamp t = new Timestamp (System.currentTimeMillis());
ScheduleJob job = new ScheduleJob(EmailJob.class.getCanonicalName() +t.toString(), EmailJob.class);

下面是将 spring applicationContext 传递给 EmailJob 的代码,以便我们可以访问 bean 和其他东西。为了实现这一点,我们需要实现 ApplicationContextAware 接口,以便 applicationContext 可用,然后将其推送到 schedulerContext。请确保我们不要将 applicationContext 放入 JobdataMap 以防您使用 JDBC 存储,因为它会产生序列化问题。

    serviceScheduler.getScheduler().getContext().put("applicationContext", ctx);
    serviceScheduler.scheduleCronJob(job, "test" + t.toString(), ServiceScheduler.DEFAULT_TRIGGER_GROUP, cronExpression);

其他不使用 wrapperscheduler 的人可以类似地使用以下方法将石英的句柄直接放入他们的代码中

    InitialContext ctx = new InitialContext();
    Scheduler scheduler = (Scheduler) ctx.lookup("Quartz");
    ScheduleJob job = new ScheduleJob(EmailJob.class.getCanonicalName() +t.toString(), Executor.class);
    scheduler.scheduleJob(job, trigger);

在电子邮件作业类中,您可以使用下面来获取 applicationContext

       applicationContext = (ApplicationContext) context.getScheduler().getContext().get(APPLICATION_CONTEXT_KEY);
       //get spring bean and do the necessary stuff

另一个重要的事情是,由于quartz 调度程序在web 应用程序之外运行,如果它在war 内部,quartz 将无法触发jobclass。它需要在jboss/[profile]/lib 中的共享jar 中。

于 2012-08-17T14:39:16.913 回答