2018年8月22日 星期三

Quartz 2.x 整合 Spring 3/4

※整合 Spring

官網連結

※build.gradle

ext {
    springVersion = '4.3.18.RELEASE'
    quartzVersion = '2.2.1'
}
    
dependencies {
    compile("org.springframework:spring-context:$springVersion")
    compile group: 'org.springframework', name: 'spring-context-support', version: springVersion
    compile group: 'org.springframework', name: 'spring-tx', version: springVersion
    compile group: 'org.quartz-scheduler', name: 'quartz', version: quartzVersion
    compile group: 'org.quartz-scheduler', name: 'quartz-jobs', version: quartzVersion
}

※一定要有 quartz 的 jar 包,否則編譯時居然是報找不到 spring jar 包的編譯錯誤,很奇怪


官網有說明,提供了 JobDetailFactoryBean 和 MethodInvokingJobDetailFactoryBean
而每一個又分成使用 SimpleTriggerFactoryBean 和 SchedulerFactoryBean


※XML設定


※使用 JobDetailFactoryBean

public class MyJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
        System.out.println("xxxxxxxxxxxxxxxxxxxxx");
        // ctx.getJobDetail().getJobDataMap().get("aaa");
    }
}




※quartz.xml 之 SimpleTriggerFactoryBean

<bean id="jobDetail"
    class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="job.MyJob" />
    <!-- <property name="durability" value="true" /> -->
    <property name="jobDataAsMap">
        <map>
            <entry key="aaa" value="111"/>
        </map>
    </property>
</bean>
    
<bean id="simpleTrigger"
    class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
    <property name="jobDetail" ref="jobDetail" />
    <property name="startDelay" value="10" />
    <property name="repeatInterval" value="2000" />
</bean>
    
<bean
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="simpleTrigger" />
        </list>
    </property>
</bean>

※durability 預設為 false,Spring 3.x 要為 true 才可以,否則會出「Jobs added with no trigger must be durable」的錯
原文是 Specify the job's durability, i.e. whether it should remain stored in the job store even if no triggers point to it anymore.
大概是說不管有沒有 trigger 指向它,是否應該保留在 job store 裡,反正 3.x 不是 true 就會報這個錯
關於 jobStore,可看官網第九篇,有三種


※quartz.xml 之 SchedulerFactoryBean

<bean id="jobDetail"
    class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="job.MyJob" />
</bean>
    
<bean id="cronTrigger"
    class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="jobDetail" />
    <property name="cronExpression" value="0/2 0 0 * * ?" />
</bean>
    
<bean
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="cronTrigger" />
        </list>
    </property>
</bean>





※MethodInvokingJobDetailFactoryBean

package job;
    
public class MyJob {
    public void getXxx() {
        System.out.println("xxxxxxxxxxxxxxxxxxxxx");
    }
}

※使用 JobDetailFactoryBean 要繼承;使用 MethodInvokingJobDetailFactoryBean 不用


※quartz.xml 之 SimpleTriggerFactoryBean

<bean id="myJob" class="job.MyJob" />
    
<bean id="jobDetail"
    class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="myJob" />
    <property name="targetMethod" value="getXxx" />
    <!-- <property name="concurrent" value="false"/> -->
</bean>
    
<bean id="simpleTrigger"
    class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
    <property name="jobDetail" ref="jobDetail" />
    <property name="startDelay" value="10" />
    <property name="repeatInterval" value="2000" />
</bean>
    
<bean
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="simpleTrigger" />
        </list>
    </property>
</bean>

※concurrent 預設為 true,如果改成 false,和 @DisallowConcurrentExecution 是一樣的意思,可在 MyJob 加這個註解,和 concurrent 不寫或寫 true 比較看看,程式碼可看這篇


※quartz.xml 之 SchedulerFactoryBean

<bean id="myJob" class="job.MyJob" />
    
<bean id="jobDetail"
    class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="myJob" />
    <property name="targetMethod" value="getXxx" />
    <!-- <property name="concurrent" value="false" /> -->
</bean>
    
<bean id="cronTrigger"
    class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="jobDetail" />
    <property name="cronExpression" value="0/2 0 0 * * ?" />
</bean>
    
<bean
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="cronTrigger" />
        </list>
    </property>
</bean>




※測試類

new ClassPathXmlApplicationContext("quartz.xml");





※整合 Spring Web

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/quartz.xml</param-value>
</context-param>
    
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

※gradle 增加 compile("org.springframework:spring-web:$springVersion"),伺服器一啟動就開始跑了



※整合 SpringWebMVC

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/quartz.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
    
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

※gradle 增加 compile("org.springframework:spring-webmvc:$springVersion"),伺服器一啟動就開始跑了




※annotation 設定



@Component
public class MyAnnotationJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
        System.out.println("xxxxxxxxxxxxxxxxxxxxx");
    }
    
    // public void getXxx() {
    //     System.out.println("xxxxxxxxxxxxxxxxxxxxx");
    // }
}




@Configuration
@ComponentScan("annotation")
public class QuartzConfiguration {
    @Autowired
    private MyAnnotationJob myJob;
    
    // @Bean
    // public JobDetailFactoryBean jobDetail() {
    // JobDetailFactoryBean job = new JobDetailFactoryBean();
    // job.setJobClass(MyAnnotationJob.class);
    // job.setDurability(true);
    // return job;
    // }
    
    @Bean
    public MethodInvokingJobDetailFactoryBean jobDetail() {
        MethodInvokingJobDetailFactoryBean job = new MethodInvokingJobDetailFactoryBean();
        job.setTargetObject(myJob);
        job.setTargetMethod("getXxx");
        return job;
    }
    
    @Bean
    public SimpleTriggerFactoryBean simpleTrigger() {
        SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
        trigger.setJobDetail(jobDetail().getObject());
        trigger.setStartDelay(10);
        trigger.setRepeatInterval(2000);
        return trigger;
    }
    
    // @Bean
    // public CronTriggerFactoryBean cronTriggerBean() {
    // CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
    // cronTriggerFactoryBean.setJobDetail(jobDetail().getObject());
    // cronTriggerFactoryBean.setCronExpression("*/2 * * * * ?");
    // return cronTriggerFactoryBean;
    // }
    
    @Bean
    public SchedulerFactoryBean schedulerFactory() {
        SchedulerFactoryBean schedule = new SchedulerFactoryBean();
        schedule.setTriggers(simpleTrigger().getObject());
        return schedule;
    }
}




※spring 測試

new AnnotationConfigApplicationContext(annotation.QuartzConfiguration.class);



※SpringWeb的 web.xml 設定

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>annotation.QuartzConfiguration</param-value>
</context-param>
    
<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
    
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>




※SpringWebMVC的 web.xml 設定

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>annotation.QuartzConfiguration</param-value>
    </init-param>
    
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
    
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>



沒有留言:

張貼留言