Custom Annotations for Quatz Timing Tasks to Realize Dynamic Configuration Tasks

Keywords: Java Spring JDK xml

Project Requirements: Timing Tasks

How to achieve it?

spring has its own timing task, jdk has its own Timer, quartz implementation.
Advantages and disadvantages, spring, annotation-based implementation, simple configuration, but rich tasks in the latter stage, after the modification of configuration is more difficult, and not easy to control.
jdk comes with it, which is easy to implement and not easy to control.
quartz, powerful and configurable.
So in order to expand the project in the future, quartz is adopted decisively and quartz jar package is introduced.
quartz-2.2.3.jar quartz-jobs-2.2.3.jar
spring 4.0

quartz implements task configuration

Write execution code:

@Component
public class TestJob {
    public void exe(){
        System.out.println("hello test");
    }
}
<!--Definition jobdetail-->
<bean id="testTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="testJob "/>
        <property name="targetMethod" value="exe"/>
    </bean>
    <!--Define triggers-->
    <bean id="handletrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="testTask"/>
        <property name="cronExpression" value="${handle_cron}"/>
    </bean>
    //Above operations, each time
    <!--Define scheduler-->
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="testtrigger"/>
                <ref bean="testtrigger1"/>
                <ref bean="testtrigger2"/>
            </list>
        </property>
        <property name="autoStartup" value="true"/>
    </bean>

Every time you add a new scheduling task, you need to add these configurations in xml. It's a real hassle.

Reduce configuration

1. analysis

In order to reduce the configuration of xml, we can observe the configuration sequence of launching a task in spring project, which is not difficult to find.

Org. spring framework. scheduling. quartz. MethodInvoking JobDetailFactory Bean and org. spring framework. scheduling. quartz. CronTriggerFactory Bean
It is a java object that instantiates a task object. It is spring's encapsulation of quartz.
Next is org. spring framework. scheduling. quartz. SchedulerFactoryBean.
Scheduler, to achieve the scheduling of the next task object
So to reduce configuration, we need to start with Scheduler FactoryBean and rewrite Scheduler FactoryBean so that it can automatically register task objects, which uses custom annotations.

2. Code Implementation

Custom Annotations

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Job {
    //Timing task grouping
    String group() default "default";
    //Task Execution Method
    String executeMethod() default "execute";
    //Execute task expression, support ${} expression, default load configuration cron expression from config/job.properties
    String cron() default "";

}

Rewritten task scheduler Scheduler FactoryBean for automatic assembly tasks


import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.quartz.JobKey;
import org.quartz.Trigger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
/**
 * 
 * @author ll
 * Dynamic Configuration Task Addition
 *Later, tasks can be configurated from the database, providing interfaces to stop, rearrange, suspend tasks and so on.
 */
@Component
public class EcrDynamicScheduler extends SchedulerFactoryBean  implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    //Default profile address
    private static final String DEFAULT_CONFIG_PATH="config/job.properties";
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
        init();
    }
    private void init(){
        //Get custom annotation bean objects
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(Job.class);
        if(beansWithAnnotation!=null){
            try {
                Collection<Object> values = beansWithAnnotation.values();
                MethodInvokingJobDetailFactoryBean jobBean=null;
                CronTriggerFactoryBean triggerBean=null;
                List<Trigger> triggerBeans=new ArrayList<Trigger>();
                //Read the default cron expression configuration file
                Properties properties=PropertiesUtils.getProperties(DEFAULT_CONFIG_PATH);
                for(Object targetObject:values){
                    //Create jobbean
                    jobBean=new MethodInvokingJobDetailFactoryBean();
                    //Get annotations on bean s
                    Job jobAnno = targetObject.getClass().getAnnotation(Job.class);
                    //Getting annotation content
                    String group = jobAnno.group();
                    String executeMethod = jobAnno.executeMethod();
                    String beanName=targetObject.getClass().getSimpleName();
                    String cron=jobAnno.cron();
                    if(cron.contains("${")){//If cron is an el expression, it is retrieved from the configuration file
                        cron=properties.getProperty(cron.substring(2, cron.indexOf("}")), "");
                    }
                    jobBean.setTargetObject(targetObject);
                    jobBean.setGroup(group);
                    jobBean.setTargetMethod(executeMethod);
                    jobBean.setBeanName(beanName+"_jobBean");  
                    //jobkey:group.beanName.executeMethod
                    jobBean.setName(beanName+"."+executeMethod);  
                    jobBean.afterPropertiesSet();
                    //Create triggers
                    triggerBean=new CronTriggerFactoryBean();
                    triggerBean.setJobDetail(jobBean.getObject());
                    triggerBean.setCronExpression(cron);
                    triggerBean.setBeanName(beanName+"_triggerBean");
                    triggerBean.setName(beanName+"."+executeMethod);  
                    triggerBean.afterPropertiesSet();
                    triggerBeans.add(triggerBean.getObject());
                }
                Trigger[] triggers =  triggerBeans.toArray(new Trigger[triggerBeans.size()]);
                //Deliver to the actuator for execution
                setAutoStartup(true);
                setTriggers(triggers);

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}

This rewritten Scheduler FactoryBean is relatively simple, but also because the project requirements are relatively simple, so there is not much to write, in fact, there are many extensible places to save task objects jobkey and jobdetail.
Implementing pause, deletion, rearrangement of task objects, etc.

Posted by sualcavab on Fri, 31 May 2019 13:15:57 -0700