栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

定时任务迁移到SnailJob的优化历程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

定时任务迁移到SnailJob的优化历程

前言
  1. 今天同事在对接我基于elasticJob二次开发的snailJob时,说需要把每个定时任务都要实现SimpleJob接口,感觉很麻烦,希望直接指定其方法,减少对接的成本
  2. Quart初始化总结:
    2.1 初始化scheduler
    2.2 将Job和触发器添加到scheduler中
    (1)Job对应于scheduler的jobDetail属性
    (2)触发器对应于scheduler的trigger属性
  3. Quart调用定时任务方法总结
    3.1 在JobDetail中指定Quart的Job,Quart调度时会触发Job的execute
    3.2 Job#execute触发器JobDataMap中指定类和方法
Spring如何集成Quart
  1. Spring集成Quart入口:

    
    	  
    	  		
    	  			
    				
    	  		
    	  
    	  
    		 
    
  2. SchedulerFactoryBean实现InitializingBean接口,故在afterPropertiesSet方法时会初始化Scheduler实例

    	public void afterPropertiesSet() throws Exception {
    		// 初始化scheduler 
    		this.scheduler = prepareScheduler(prepareSchedulerFactory());
    		try {
    		         ..........
    		         //注册定时任务
    				registerJobsAndTriggers();
    		}
    	}
    

    2.1 SchedulerFactoryBean继承SchedulerAccessor,其triggers属性中包含所有的定时任务,在registerJobsAndTriggers方法中将trigger加入到Sheduler

  3. 将trigger加入到Sheduler(SchedulerAccessor#addTriggerToScheduler)

    	private boolean addTriggerToScheduler(Trigger trigger) throws SchedulerException {
    		//从trigger中取出jobDetail
    		JobDetail jobDetail = (JobDetail) trigger.getJobDataMap().remove("jobDetail");
    		if (jobDetail != null && this.jobDetails != null && !this.jobDetails.contains(jobDetail) &&
    					(this.overwriteExistingJobs || getScheduler().getJobDetail(jobDetail.getKey()) == null)) {
    			    //将trigger加入到Sheduler	
    				getScheduler().scheduleJob(jobDetail, trigger);
    				this.jobDetails.add(jobDetail);
    		}
    	}
    

    3.1 首先看一下,配置trigger长啥样?见下方
    (1) trigger主要配置定时任务的job以及触发器,那Quart怎样触发Job方法?

    	
    		
    		
    		
    	
    
Quart是如何指定执行方法
  1. Job配置如下
    1.1 主要配置了Job所在的类以及对应的方法
    1.2 MethodInvokingJobDetailFactoryBean继承ArgumentConvertingMethodInvoker(继承MethodInvoker)

    
    		
    			
    		
    		
    			run
    		
    
    
  2. MethodInvokingJobDetailFactoryBean实现FactoryBean,在getObject时返回JobDetail
    2.1 在其afterPropertiesSet方法时初始化jobDetail

    public void afterPropertiesSet() throws ClassNotFoundException, NoSuchMethodException {
    	// 初始化methodInvoker的methodObject属性
    	prepare();
    	
    	// Consider the concurrent flag to choose between stateful and stateless job.(默认为MethodInvokingJob)
    	Class jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);
    	
    	// Build JobDetail instance.
    	JobDetailImpl jdi = new JobDetailImpl();
    	jdi.setName(name != null ? name : toString());
    	jdi.setGroup(this.group);
    	// MethodInvokingJob通过QuartzJobBean实现Quart的Job
    	jdi.setJobClass((Class) jobClass);
    	jdi.setDurability(true);
    	// 重点:最终会在JobRunShell时,将MethodInvokingJobDetailFactoryBean设置到MethodInvokingJob的methodInvoker属性
    	jdi.getJobDataMap().put("methodInvoker", this);
    	this.jobDetail = jdi;
    }
    

    3.2 MethodInvoker#prepare分析

    public void prepare() throws ClassNotFoundException, NoSuchMethodException {
    	//用户设置的定时任务类
    	Class targetClass = getTargetClass();
    	//设置的定时任务方法
    	String targetMethod = getTargetMethod();
    	// 用户设置的定时任务方法参数
    	Object[] arguments = getArguments();
    	Class[] argTypes = new Class[arguments.length];
    	for (int i = 0; i < arguments.length; ++i) {
    		argTypes[i] = (arguments[i] != null ? arguments[i].getClass() : Object.class);
    	}
    	
    	try {
    		this.methodObject = targetClass.getMethod(targetMethod, argTypes);
    	}
    }
    
  3. MethodInvokingJobDetailFactoryBean$MethodInvokingJob#executeInternal执行任务

    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
    	try {
    		//this.methodInvoker.invoke()调用指定任务方法
    		context.setResult(this.methodInvoker.invoke());
    	}catch (InvocationTargetException ex) {
    		.....
    }
    

    3.1 MethodInvoker#invoke分析

    public Object invoke() throws InvocationTargetException, IllegalAccessException {
    	// In the static case, target will simply be {@code null}.
    	Object targetObject = getTargetObject();
    	Method preparedMethod = getPreparedMethod();
    	if (targetObject == null && !Modifier.isStatic(preparedMethod.getModifiers())) {
    		throw new IllegalArgumentException("Target method must not be non-static without a target");
    	}
    	ReflectionUtils.makeAccessible(preparedMethod);
    	return preparedMethod.invoke(targetObject, getArguments());
    }
    
SnailJob是如何封装Quart简单介绍
  1. SnailJob是基于elatiscJob的代码改造出来的公司内部调度框架
  2. SnailJob创建JobDetail代码示例
    private JobDetail createJobDetail() {
         JobDetail result = JobBuilder.newJob(LiteJob.class).withIdentity(getJobConfig().getJobName()).build();
         result.getJobDataMap().put(JOB_EXECUTOR_DATA_MAP_KEY, jobExecutor);
         return result;
     }
    
  3. Quart调度触发任务的调用栈
优化代码展示
  1. 在执行任务时,多了一层判断,如果是spring方式的定时任务,则直接反射调用其指定的方法
    1.1 直接加if判断,感觉不优雅(后期优化,哈哈哈)
if(snailJob instanceof JobDetailImpl){
	  JobDataMap jobDataMap = ((JobDetailImpl) snailJob).getJobDataMap();
      MethodInvokingJobDetailFactoryBean methodInvoker = (MethodInvokingJobDetailFactoryBean) jobDataMap.get("methodInvoker");
      methodInvoker.invoke();
  }else{
      ((SimpleJob)snailJob).execute(shardingContexts.createShardingContext(item));
  }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/424168.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号