1. 程式人生 > 實用技巧 >Spring+Quartz叢集環境搭建

Spring+Quartz叢集環境搭建

所需依賴

<dependencies>
    <!--核心包-->
    <dependency>
      <groupId>org.quartz-scheduler</groupId>
      <artifactId>quartz</artifactId>
      <version>2.3.0</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</
groupId> <artifactId>spring-context-support</artifactId> <version>4.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>
4.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.9.RELEASE</version> </dependency> <dependency> <groupId
>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.1.9.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.1.9.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.24</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.1.9.RELEASE</version> </dependency> </dependencies>

配置檔案quartz.properties

#是否用這個配置檔案 預設不使用
#org.quartz.jobStore.useProperties= true
#表的字首名
org.quartz.jobStore.tablePrefix = qrtz_
#是否使用叢集
org.quartz.jobStore.isClustered = true
#檢查時間間隔
org.quartz.jobStore.clusterCheckinInterval =5000
#最大時間間隔
org.quartz.jobStore.misfireThreshold =60000
org.quartz.jobStore.txIsolationLevelReadCommitted= true
#=========================================================================================
#記憶體
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#代理
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#=========================================================================================
#如果使用叢集,id必須唯一,所以必須自動生成
org.quartz.scheduler.instanceId =AUTO
#排程器名稱
org.quartz.scheduler.instanceName =MY_CLUSTERED_JOB_SCHEDULER
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
#=========================================================================================
# Configure ThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

applicationContext.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置掃描的包-->
    <context:component-scan base-package="com.otc"/>
    <!--資料庫連線池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/quartz"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <!--分散式配置-->

    <!--配置執行緒池-->
    <bean name="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="15"/>
        <property name="maxPoolSize" value="25"/>
        <property name="queueCapacity" value="100"/>
    </bean>

    <!--配置事務管理器-->
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--配置job詳情-->
    <!--任務一-->
    <bean name="jobDetail_1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.otc.HelloJob"/>
        <!--開啟持久化-->
        <property name="durability" value="true"/>
        <!--是否覆蓋-->
        <property name="requestsRecovery" value="false"/>
    </bean>

    <!--任務二-->
    <bean name="jobDetail_2" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.otc.HelloJob2"/>
        <!--開啟持久化-->
        <property name="durability" value="true"/>
        <!--是否覆蓋-->
        <property name="requestsRecovery" value="false"/>
    </bean>

    <!--任務三-->
    <bean name="jobDetail_3" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.otc.Test11"/>
        <!--開啟持久化-->
        <property name="durability" value="true"/>
        <!--是否覆蓋-->
        <property name="requestsRecovery" value="false"/>
    </bean>


    <!--配置觸發時間-->
    <bean id="cronTrigger_1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail">
        <ref bean="jobDetail_1"/>
    </property>
    <!-- 每1秒鐘執行一次 -->
    <property name="cronExpression">
        <value>0/1 * * * * ?</value>
    </property>
    <property name="timeZone">
        <value>GMT+8:00</value>
    </property>
</bean>

    <bean id="cronTrigger_2" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail">
        <ref bean="jobDetail_2"/>
    </property>
    <!-- 每5秒鐘執行一次 -->
    <property name="cronExpression">
        <value>0/5 * * * * ?</value>
    </property>
    <property name="timeZone">
        <value>GMT+8:00</value>
    </property>
</bean>

    <bean id="cronTrigger_3" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail">
            <ref bean="jobDetail_3"/>
        </property>
        <!-- 每10秒鐘執行一次 -->
        <property name="cronExpression">
            <value>0/10 * * * * ?</value>
        </property>
        <property name="timeZone">
            <value>GMT+8:00</value>
        </property>
    </bean>


    <!--定義排程器,並將Trigger註冊到排程器中-->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!--配置檔案-->
        <property name="configLocation" value="classpath:quartz.properties"/>
        <!--資料來源-->
        <property name="dataSource" ref="dataSource"/>
        <!--任務唯一的名稱,將持久化到資料庫-->
        <property name="schedulerName" value="mavenTest2"/>
        <!--每臺叢集機器部署應用的時候更新觸發器-->
        <property name="overwriteExistingJobs" value="true"/>
        <property name="applicationContextSchedulerContextKey" value="appl"/>
        <!-- 設定自動啟動 -->
        <property name="autoStartup" value="true"/>
        <!--執行緒池-->
        <property name="taskExecutor" ref="executor"/>
        <!--事務-->
        <property name="transactionManager" ref="transactionManager"/>
        <property name="triggers">
            <list>
                <ref bean="cronTrigger_1"/>
                <ref bean="cronTrigger_2"/>
                <ref bean="cronTrigger_3"/>
            </list>
        </property>
    </bean>
</beans>

job類 繼承QuartzJobBean或者實現Job介面

public class HelloJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        System.out.println("任務 1 當前時間:  "+format);
    }
}

測試

public class TestQuartzSpring {
    public static void main(String[] args) {
        //工廠啟動,排程器啟動,任務排程開始
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    }
}

可以同時啟動多個任務來檢視效果

分散式方式使用資料庫,任務相關的資訊存入到資料庫中,所有的節點連線到同一個資料庫,能夠進行共享資料,實現任務不重複跑不漏跑

其中持久化時:

如果需要使用單個方法設定定時任務,是不能持久化的:
 Spring從2.0.2開始便不再支援Quartz。具體表現在Quartz+Spring把Quartz的Task例項化進入資料庫時,會產生:Serializable的錯誤:
Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable

所以需要自己定義一個類實現MethodInvoker的邏輯
使用JobDetail的jobClass和JobDataAsMap屬性定義一個類來實現,思路是這樣,但我沒成功.......所以就不放程式碼了