xxjob怎么启动_spring+quartz两种整合方式:代码创建job+xml配置创建job

quartz交流QQ群:77383408,喜欢的同行一起来探讨问题吧

最近在项目中需要用到quartz,开始使用的xml配置创建的job,一切ok。后来觉得每次添加任务都要写一大段xml,就将job放入了数据库,在spring启动时去启动数据库中保存的所有job。

其中遇到问题,无法注入spring管理的bean。本文是解决方案,研究了几天,终于找到原因了!

首先,本文实现使用的是内存型,没有持久化到数据库。

一、quartz.properties文件

#调度器名,无关紧要,名字任意定

org.quartz.scheduler.instanceName = XXScheduler

org.quartz.scheduler.instanceId = AUTO

#============================================================================

# Configure ThreadPool   配置数据库连接池

#============================================================================

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool

org.quartz.threadPool.threadCount = 12

org.quartz.threadPool.threadPriority = 5

#============================================================================

# Configure JobStore  配置做业存储方式

#============================================================================

#相当于扫描频率,如果系统基于秒级,应培植成1000,quartz默认为分级(60000)

org.quartz.jobStore.misfireThreshold = 1000

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

二、创建任务Job

方法一:使用xml方式配置job

0/1 * * * * ?

好了,至此使用xml方式配置job就全部完毕了。

其中值得注意的是下面两句代码:自定义MyJobFactory,在job类里面才可以注入spring的service。

public class MyJobFactory extends AdaptableJobFactory {

// 这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.

@Autowired

private AutowireCapableBeanFactory capableBeanFactory;

protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {

// 调用父类的方法

Object jobInstance = super.createJobInstance(bundle);

// 进行注入,这属于Spring的技术,不清楚的可以查看Spring的API.

capableBeanFactory.autowireBean(jobInstance);

return jobInstance;

}

}

/**

* Job任务类,实现Job接口,可以成功注入service

*/

public class JobClassTest implements Job {

@Autowired

private ProductBaseDao productBaseDao;

@Override

public void execute(JobExecutionContext context) throws JobExecutionException {

ProductBase p = productBaseDao.load(ProductBase.class, 2);

System.out.println("注入service成功!查询结果为:"+p);

}

}

至此,启动容器,job成功启动。

方式二:使用代码创建Job

表结构:本示例只需要一张表即可!

数据库有了记录,那么我们就需要在spring容器启动后,将所有记录获取出来,并通过代码创建每一个job。

在applicationContext.xml配置文件最末加上这一句,即可在spring启动后,去执行指定类中的方法。

/**

* 在Spring容器将所有的Bean都初始化完成之后的操作

*/

public class InstantiationTracingBeanPostProcessor implements ApplicationListener {

@Autowired

private TimerJobService timerJobService;

@Autowired

private MyJobFactory myJobFactory;

@Override

public void onApplicationEvent(ContextRefreshedEvent event) {

// 避免onApplicationEvent方法被执行两次

if(event.getApplicationContext().getParent() == null){

try {

// 获取Scheduler对象,并自定义jobFactory

Scheduler scheduler = QuartzUtil.getInstance();

scheduler.setJobFactory(myJobFactory);

// 查询所有正常状态的定时任务,并在容器启动后,启动任务

List jobs = timerJobService.getNormalList();

for(TimerJob record : jobs){

Integer id = record.getId();

String name = record.getJobName()+"_"+id;

String group = record.getJobGroup()+"_"+id;

// 加载job类

Class extends Job> clazz = null;

try {

clazz = (Class extends Job>) Class.forName(record.getClassName());

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

//生成jobDetail

JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(name, group).build();

//表达式调度构建器

CronScheduleBuilder cornSB= CronScheduleBuilder.cronSchedule(record.getCronExpression());

//生成触发器

CronTrigger trigger = (CronTrigger)TriggerBuilder.newTrigger().withIdentity(name, group).withSchedule(cornSB).build();

//添加job

scheduler.scheduleJob(jobDetail, trigger);

}

//开始执行shceduler

scheduler.start();

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

其中创建Scheduler实例方法为:

public class QuartzUtil {

private static SchedulerFactory ssf = new StdSchedulerFactory();

/**

* 获取Scheduler实例,使用工厂模式获取

* @return

*/

public static Scheduler getInstance(){

Scheduler sched = null;

try {

sched = ssf.getScheduler();

} catch (SchedulerException e) {

e.printStackTrace();

}

return sched;

}

}

其中关键代码为:scheduler.setJobFactory(myJobFactory) ;同xml配置一样,需要指定自定义的JobFactory。

最开始,我是这样设置的:scheduler.setJobFactory(new MyJobFactory());

可是这样的结果就是,任务全部启动了,可是在job任务类注入不了bean。思考了很久,才突然发现, MyJobFactory是使用new关键字实例化出来的,在spring中,自己new出来的都不会交给spring的context去管理!!!

既然找到问题所在,解决就简单多了,只需要将MyJobFactory交给spring中去,再在上文通过注解注入即可!

在MyJobFactory.java类最上面添加@component注解,启动时spring去扫描组件会将该类注入。

@Component

public class MyJobFactory extends AdaptableJobFactory {......}

至此,问题全部解决,两种创建job的方法,个人觉得第二种比较简单。需要新增任务时,只需要在数据库添加一条记录,再添加一个对应的job类即可。

有了这一张表,同样可以配置后台页面,实现对任务的控制,这里就不讲啦!

最后,欢迎喜欢quartz的人,加入QQ群:77383408

把你的问题说出来集思广益,避免大家重蹈覆辙。

代码中使用 XXL-Job 创建定时任务返回 302 状态码,通常意味着发生了重定向。以下是一些可能的解决办法: ### 1. 检查登录状态 XXL-Job 的调度中心一般需要登录才能进行操作。如果未登录或者登录状态失效,可能会重定向到登录页面,从而返回 302 状态码。可以在代码中确保登录状态的有效性,例如在发起创建定时任务请求前,先进行登录操作并获取有效的会话信息。 ```java // 示例:模拟登录操作获取会话信息 CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost("http://xxl-job-admin/login"); List<NameValuePair> params = new ArrayList<>(); params.add(new BasicNameValuePair("username", "your_username")); params.add(new BasicNameValuePair("password", "your_password")); httpPost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8)); CloseableHttpResponse response = httpClient.execute(httpPost); // 获取会话信息,如 Cookie 等,后续请求携带该信息 Header[] cookies = response.getHeaders("Set-Cookie"); ``` ### 2. 检查请求路径 确保创建定时任务的请求路径正确。如果路径错误,可能会导致重定向。可以参考 XXL-Job 的官方文档或者调试工具,确认正确的请求路径。 ```java // 示例:创建定时任务请求 HttpPost createJobPost = new HttpPost("http://xxl-job-admin/jobinfo/add"); // 设置请求头,携带会话信息 for (Header cookie : cookies) { createJobPost.addHeader(cookie); } // 设置请求参数 List<NameValuePair> jobParams = new ArrayList<>(); jobParams.add(new BasicNameValuePair("jobGroup", "1")); jobParams.add(new BasicNameValuePair("cron", "0 0 0 * * ?")); // 其他参数... createJobPost.setEntity(new UrlEncodedFormEntity(jobParams, StandardCharsets.UTF_8)); CloseableHttpResponse jobResponse = httpClient.execute(createJobPost); ``` ### 3. 检查权限配置 确认当前用户是否具有创建定时任务的权限。如果权限不足,可能会被重定向到权限不足提示页面。可以在 XXL-Job 的管理界面检查用户权限配置。 ### 4. 检查调度中心配置 检查 XXL-Job 调度中心的配置,如是否开启了重定向策略等。确保调度中心的配置不会导致不必要的重定向。 ### 5. 调试和日志分析 使用调试工具(如 Postman)或者在代码中添加日志,分析请求和响应的详细信息。查看重定向的目标地址,从而定位问题所在。 ```java // 示例:打印响应信息 int statusCode = jobResponse.getStatusLine().getStatusCode(); if (statusCode == 302) { Header locationHeader = jobResponse.getFirstHeader("Location"); if (locationHeader != null) { String redirectUrl = locationHeader.getValue(); System.out.println("重定向地址: " + redirectUrl); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值