Spring Boot:在Quartz作业中使用@Autowired

时间:2016-06-03 21:07:29

标签: java spring quartz-scheduler inject

我设法在Spring Boot(版本4.2.5)中使用JobStoreTX持久存储来配置和调度Quartz作业。这是我安排工作的方式。 第一:

public class MyJob implements Job{
    @Autowired
    IService service;

    @Override
      public void execute(JobExecutionContext context) throws JobExecutionException {
        service.doSomething();
      }
}

@Autowired似乎无法在Quartz作业实现中工作,因为它不会被Spring实例化。因此,我面临着名的JavaNullPointerException。

其次,为了在Quartz作业中掌握Spring托管bean,我使用org.springframework.scheduling.quartz.SchedulerFactoryBean来管理Quartz生命周期:

public class MyJob implements Job{

    @Override
      public void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            ApplicationContext applicationContext = (ApplicationContext) context.getScheduler().getContext().get("applicationContext");
            IService service= applicationContext.getBean(IService.class);
            service.getManualMaxConfig();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
      }
}

然后:

<bean id="scheduler"
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="applicationContextSchedulerContextKey" value="applicationContext" />

</bean>

令人遗憾的是,我也面临着JavaNPE。 我也试试这些建议,但是徒劳无功..

LINK

我正在做什么错了?

更新1: 在尝试注入服务之前,我试图传递一些Params,因为@ ritesh.garg建议。

public class MyJob implements Job{

    private String someParam;
    private int someParam2;

    public void setSomeParam(String someParam) {
        this.someParam = someParam;
    }


    public void setSomeParam2(int someParam2) {
        this.someParam2 = someParam2;
    }

    @Override
      public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("My job is running with "+someParam+' '+someParam2);
      }
}

我的jobBean.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

 <bean id="scheduler"
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="applicationContextSchedulerContextKey" value="applicationContext" />

</bean> 


<bean id="myJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="com.quartz.service.MyJob"/>
    <property name="jobDataAsMap">
        <map>
            <entry key="someParam" value="some value"/>
            <entry key="someParam2" value="1"/>
        </map>
    </property>
</bean>

</beans>

我不知道为什么,但参数没有通过并打印出来:

My job is running with null 0

Ps:我将jobBean.xml导入Application.java。所以我不知道我错过了什么?

更新2:以下是我的详细代码:

@Component
public class JobScheduler{
    Timer timer = new Timer();    
   @PostConstruct
    public void distributeAutomaticConf(){
        try {
            timer.schedule(new ServiceImpl(), 10000);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }       
    }  
}

服务Impl:

@Transactional
@Component
public class ServiceImpl extends TimerTask implements IService{

@Override
    public void run() {
         final SchedulerFactory factory = new StdSchedulerFactory();
            Scheduler scheduler = null;

            try {
              scheduler = factory.getScheduler();


                  final JobDetailImpl jobDetail = new JobDetailImpl();
                  jobDetail.setName("My job executed only once.. ");
                  jobDetail.setJobClass(MyJob.class);

              SimpleTrigger trigger = (SimpleTrigger) newTrigger()
                        .withIdentity("trigger_", "group_")
                        .build(); 
              scheduler.start();
              scheduler.scheduleJob(jobDetail, trigger);

              System.in.read();
              if (scheduler != null) {
                scheduler.shutdown();
              }
            } catch (final SchedulerException e) {
              e.printStackTrace();
            } catch (final IOException e) {
              e.printStackTrace();
            }
    }
}

MyJob:

public class MyJob extends QuartzJobBean{

    @Autowired
    IService service;
    @Override
    protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {         SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);    
        service.doSomething();  
    }
}

jobBean.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

 <bean id="scheduler"
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="applicationContextSchedulerContextKey" value="applicationContext" />

</bean> 


<bean id="myJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="com.quartz.service.MyJob"/>
    <property name="jobDataAsMap">
        <map>
            <entry key="someParam" value="some value"/>
            <entry key="someParam2" value="1"/>
        </map>
    </property>
</bean>

</beans>

quartz.properties:

org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

org.quartz.jobStore.misfireThreshold = 60000

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
#org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_

org.quartz.dataSource.myDS.driver = org.postgresql.Driver
org.quartz.dataSource.myDS.URL = jdbc:postgresql://localhost:5432/myDB
org.quartz.dataSource.myDS.user = admin
org.quartz.dataSource.myDS.password = admin
org.quartz.dataSource.myDS.maxConnections = 10

org.quartz.scheduler.skipUpdateCheck=true

console:

java.lang.NullPointerException: null
    at com.quartz.service.MyJob.executeInternal(MyJob.java:27) ~[classes/:na]
    at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113) ~[spring-context-support-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.2.1.jar:na]
    at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [quartz-2.2.1.jar:na]

2016-06-05 11:35:16.839 ERROR 25452 --- [eduler_Worker-1] org.quartz.core.ErrorLogger              : Job (DEFAULT.My job executed only once..  threw an exception.

org.quartz.SchedulerException: Job threw an unhandled exception.
    at org.quartz.core.JobRunShell.run(JobRunShell.java:213) ~[quartz-2.2.1.jar:na]
    at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [quartz-2.2.1.jar:na]
Caused by: java.lang.NullPointerException: null
    at com.quartz.service.MyJob.executeInternal(MyJob.java:27) ~[classes/:na]
    at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113) ~[spring-context-support-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.2.1.jar:na]
    ... 1 common frames omitted

4 个答案:

答案 0 :(得分:2)

我过去经历过同样的问题。我对这个问题的理解是,只需使用@Autowired注释就不能在spring上下文中实例化bean,而不能在石英上下文中注入。

我设法通过使用基于setter的依赖注入来解决它。但是在原帖中添加的“LINK”中也提到了相同的内容。

从链接中粘贴相关信息:

更新:将implements Job替换为extends QuartzJobBean

public class MyJob extends QuartzJobBean {
    private String someParam;
    private int someParam2;

    public void setSomeParam(String someParam) {
        this.someParam = someParam;
    }

    public void setSomeParam2(String someParam2) {
        this.someParam2 = someParam2;
    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("My job is running with "+someParam+' '+someParam2);
    }
}

这里,someParam和someParam2是通过setter依赖注入注入的。现在完成这一操作的另一部分是在jobDataAsMap

中传递someParam和someParam2
<bean id="myJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="com.my.MyJob"/>
    <property name="jobDataAsMap">
        <map>
            <entry key="someParam" value="some value"/>
            <entry key="someParam2" value="1"/>
        </map>
    </property>
</bean>

在你的情况下,它将是一个值-ref =“IserviceBeanId”,而不是条目中的'value'。如果这对你没有用,我会感到惊讶和好奇。

答案 1 :(得分:1)

我解决了在我的工作中实现“InitializingBean”的问题;

    public class MyJob extends QuartzJobBean implements InitializingBean {

        private String someParam;
        private int someParam2;

        public void setSomeParam(String someParam) {
            this.someParam = someParam;
        }

        public void setSomeParam2(String someParam2) {
            this.someParam2 = someParam2;
        }

        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            System.out.println("My job is running with "+someParam+' '+someParam2);
        }
        @Override
        public void afterPropertiesSet() throws Exception {
        }
    }

答案 2 :(得分:0)

从我见过的大多数示例中,正确的方法是将Job接口实现为@Component

@Component
public class MyJob implements Job{ 
     @Autowired IService service; 
     @Override 
     public void execute(JobExecutionContext context) throws JobExecutionException{ 
          service.doSomething();
     } 
}

答案 3 :(得分:0)

我们可以使用 JobDataMap 来传递对象。

示例:这里的 restTemplate 是自动装配的。

JobDataMap newJobDataMap = new JobDataMap();
newJobDataMap.put("restTemplate", restTemplate);

JobDetail someJobDetail = JobBuilder
.newJob(QuartzJob.class)
.withIdentity(jobName, GROUP)
.usingJobData(newJobDataMap)
.build();