使用Google Guice/Dagger在Java Web应用中创建Quartz Job执行的对象链。

huangapple go评论73阅读模式
英文:

Creating Object chain in Quartz Job execution using Google Guice/Dogger in Java Web App

问题

以下是您要求的翻译内容:

我开始在我的Java Web应用程序中使用Quartz创建cron作业,以执行其中一个清理任务。实际作业按预期触发,Quartz作业执行没有问题。从下面的代码片段中,当我尝试使用MyService调用作业的所需方法时,依赖关系不起作用。

MyService类的对象没有被创建。因此,我得到了空指针异常。为了避免这种情况,我尝试使用Google Guice(也尝试了Dogger)来进行依赖注入管理,但MyService对象的创建取决于其他类。

假设在这个例子中有一个CustomerService,这个CustomerService依赖于其他类,而这些类又依赖于其他一些类,依此类推。因此,我将使用Guice或Dogger来创建对象创建链。

代码片段:

import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import org.quartz.Job;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;

@Singleton
public class CustomJobFactory implements JobFactory {

   @Inject
   private Injector injector;

   @Override
   public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
      return (Job) injector.getInstance(bundle.getJobDetail().getJobClass());
   }
}

public class QuartzJobHelper  {

   private final Scheduler scheduler;

   @Inject
   public QuartzSchedulerImpl(Scheduler scheduler, CustomJobFactory customJobFactory) {
      this.scheduler = scheduler;
      try {
         this.scheduler.setJobFactory(customJobFactory);
      } catch (SchedulerException e) {
         e.printStackTrace();
      }
   }

   public static void executeJob() throws Exception {
      // Guice注入器用于创建实例。
      Injector injector = Guice.createInjector(new MyModule());
      JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("myjob", "mygroup")
            .build();
      Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mytrigger", "mygroup")
            .withSchedule(CronScheduleBuilder.cronSchedule("0/1 * * * * ?")).build();

      SchedulerFactory schedulerFactory = new StdSchedulerFactory();
      Scheduler scheduler = schedulerFactory.getScheduler();

      // 告知Quartz调度器使用我们的工厂。
      scheduler.setJobFactory(injector.getInstance(CustomJobFactory.class));
      scheduler.scheduleJob(jobDetail, trigger);

      // 启动调度器。
      scheduler.start();
   }
}

import org.quartz.spi.JobFactory;
import java.io.IOException;

public class MyModule extends AbstractModule {

   @Override
   protected void configure() {
       bind(JobFactory.class).to(MyJobFactory.class);
	   bind(MyService.class).to(MyServiceImpl.class);
       bind(CustomerService.class).to(CustomerServiceImpl.class);
       bind(MyDao.class).to(MyDaoImpl.class);
       bind(CustomCache.class).to(CustomCacheImpl.class);
       bind(ProxyDao.class).to(ProxyDaoImpl.class);
       bind(RequestDao.class).to(DefaultRequestDao.class);
	   // ...
   }
}

public class MyJob extends org.quartz.Job {

 @Inject
 MyService service;

 public void execute(JobExecutionContext jobContext) throws JobExecutionException {
	  service.cleanupJunkData();
     }    
}

class MyService {
 void cleanupJunkData();
}

@Named
class MyServiceImpl implments MyService {
   
   private CustomerService cs; 
   private MyDao dao;
   private CustomCache cache;
   
   @Inject 
   public MyServiceImpl(CustomerService cs, MyDao dao, CustomCache cache) {
     this.cs = cs;
	 this.dao=dao;
	 this.cache = cache;
   }
   
   @Override
   public void cleanupJunkData() {
     List<Customer> customerData = cs.getCustomerData(dao.getExpiredCustId());
	 cache.clear(customerData);
   }
}

public class MainClass {
  public static void main(String[] args) {
      QuartzJobHelper.executeJob();
  }
}

有人可以建议如何处理Quartz作业中的对象创建吗?

英文:

I started to create a cron job using Quartz in my Java web application to execute one of cleanup task. The actual job is firing as expected and no
problem with the Quatrz job execution. From the below code snippet When I try to use MyService to call the required method as part of job, Dependency is not working.

Object for the MyService class is not created. So I'm getting a null pointer exception. To avoid this I tried to use Google Guice (tried dogger as well) to manage
dependency injection but MyService object creation depends on other classes.

Let's say in this example CustomerService and this CustomerService depends on other classes and those classes depends on some other etc.. So I am going to end up creating object creation chain by using Guice or Dogger.

Code snippet:

  import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import org.quartz.Job;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
@Singleton
public class CustomJobFactory implements JobFactory {
@Inject
private Injector injector;
@Override
public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
return (Job) injector.getInstance(bundle.getJobDetail().getJobClass());
}
}
public class QuartzJobHelper  {
private final Scheduler scheduler;
@Inject
public QuartzSchedulerImpl(Scheduler scheduler, CustomJobFactory customJobFactory) {
this.scheduler = scheduler;
try {
this.scheduler.setJobFactory(customJobFactory);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
public static void executeJob() throws Exception {
// The Guice injector used to create instances.
Injector injector = Guice.createInjector(new MyModule());
JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity(&quot;myjob&quot;, &quot;mygroup&quot;)
.build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(&quot;mytrigger&quot;, &quot;mygroup&quot;)
.withSchedule(CronScheduleBuilder.cronSchedule(&quot;0/1 * * * * ?&quot;)).build();
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// Inform Quartz scheduler to use our factory.
scheduler.setJobFactory((injector.getInstance(CustomJobFactory.class));
scheduler.scheduleJob(jobDetail, trigger);
// Start the scheduler.
scheduler.start();
}

}

import org.quartz.spi.JobFactory;
import java.io.IOException;

public class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(JobFactory.class).to(MyJobFactory.class);
bind(MyService.class).to(MyServiceImpl.class);
bind(CustomerService.class).to(CustomerServiceImpl.class);
bind(MyDao.class).to(MyDaoImpl.class);
bind(CustomCache.class).to(CustomCacheImpl.class);
bind(ProxyDao.class).to(ProxyDaoImpl.class);
bind(RequestDao.class).to(DefaultRequestDao.class);
|
|
|
etc.. Likewise so many dependencies are there to inject but finding 100&#39;s of dependencies.
}
}
public class MyJob extends org.quartz.Job {
@Inject
MyService service;
public void execute(JobExecutionContext jobContext) throws JobExecutionException {
service.cleanupJunkData();
}    
}
class MyService {
void cleanupJunkData();
}
@Named
class MyServiceImpl implments MyService {
private CustomerService cs; 
private MyDao dao;
private CustomCache cache;
@Inject 
public MyServiceImpl(CustomerService cs, MyDao dao, CustomCache cache) {
this.cs = cs;
this.dao=dao;
this.cache = cache;
}
@Override
public void cleanupJunkData() {
List&lt;Customer&gt; customerData = cs.getCustomerData(dao.getExpiredCustId());
cache.clear(customerData);
}
}
public Class MainClass {
public static void main(Stirng[] args) {
QuartzJobHelper.executeJob();
}
}

Could someone suggest how to deal with object creation in Quartz job?

答案1

得分: 1

你的示例中并未提供任何Guice特定的代码但你想要创建一个`JobFactory`,它将负责在作业被触发时进行注入

```java 
public class GuiceJobFactory implements JobFactory {
	@Inject
    private Injector guiceInjector;
	
	@Override
	public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
		return (Job) guiceInjector.getInstance(bundle.getJobDetail().getJobClass());
	}
}

你可以根据需要创建这个类,但你需要想办法将Injector传递给它。

编辑

根据你的评论,我不太明白。我们有以下设置(带有多个作业):

JobThatDoesSomething:
@Inject Service1 service1;

Service1:
@Inject Dao1 dao1;
@Inject Dao2 dao2;
@Inject ValidationFactory validationFactory;

ValidationFactory:
@Inject ValidationProvider provider;

从高层次上看,这只是一个单个作业的层次结构。我们大约有100个具有相同级别的注入依赖关系的作业。从我所了解的情况来看,这与你的情况完全相同?

你是在说什么?你的工厂会导致:

  • MyService没有被注入?
  • MyService.CustomerService没有被注入?
  • 等等?

编辑 2

你需要以某种方式创建你的注入器。我已经添加了你的主要代码,并展示了如何使用CustomModuleJobFactory

public Class MainClass {
  public static void main(String[] args) {
       // 在这里创建你的注入器
       Injector injector = Guice.createInjector(new CustomModule());

       SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
        Scheduler scheduler = schedFact.getScheduler();
        scheduler.setJobFactory(new GuiceJobFactory(injector));  // 在这里使用它
        scheduler.start();
         
        // 定义作业并将其与我们的HelloJob类绑定
        JobBuilder jobBuilder = JobBuilder.newJob(MyJob.class);
        JobDataMap data = new JobDataMap();
        data.put("latch", this);
         
        JobDetail jobDetail = jobBuilder.usingJobData("example", "com.QuartzSchedulerExample") 
                .usingJobData(data)
                .withIdentity("myJob", "group1")
                .build();
         
         
        // 每天在当前时间的基础上加1分钟触发
        Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("myTrigger", "group1")
        .startAt(DateBuilder.todayAt(10, 20, 20))
        .withSchedule(CronScheduleBuilder.cronSchedule("0 " + (min + 1) + " " + hour + " * * ? *"))     
        .build();
         
        // 告诉Quartz使用我们的触发器安排作业
        scheduler.scheduleJob(jobDetail, trigger);
  }
}
英文:

You haven't provided any Guice specific code in your example, but you want to create a JobFactory, which will be responsible for injecting each job as they are fired:

public class GuiceJobFactory implements JobFactory {
	@Inject
    private Injector guiceInjector;
	
	@Override
	public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
		return (Job) guiceInjector.getInstance(bundle.getJobDetail().getJobClass());
	}
}

You can create this however you choose, but you'll need to somehow get the Injector into it.

Edit

From your comment, I don't really understand. We have the following setup (with multiple jobs):

JobThatDoesSomething:
@Inject Service1 service1;

Service1:
@Inject Dao1 dao1;
@Inject Dao2 dao2;
@Inject ValidationFactory validationFactory;

ValidationFactory:
@Inject ValidationProvider provider;

This is at a high level the hierarchy of just a single job. We have about 100 that have the same level of injected dependencies. From what I can tell, this is exactly the same as you?

What are you saying? That with this factory your:

  • MyService is not injected?
  • MyService.CustomerService is not injected?
  • Etc?

Edit 2

You need to create your injector somehow. I've added your main code, with an example of how you would use your CustomModule and JobFactory:

public Class MainClass {
  public static void main(Stirng[] args) {
       // You need to create your injector here
       Injector injector = Guice.createInjector(new CustomModule());

       SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
        Scheduler scheduler = schedFact.getScheduler();
        scheduler.setJobFactory(new GuiceJobFactory(injector));  // Use it here
        scheduler.start();
         
        // define the job and tie it to our HelloJob class
        JobBuilder jobBuilder = JobBuilder.newJob(MyJob.class);
        JobDataMap data = new JobDataMap();
        data.put(&quot;latch&quot;, this);
         
        JobDetail jobDetail = jobBuilder.usingJobData(&quot;example&quot;, &quot;com.QuartzSchedulerExample&quot;) 
                .usingJobData(data)
                .withIdentity(&quot;myJob&quot;, &quot;group1&quot;)
                .build();
         
         
        // Fire at curent time + 1 min every day
        Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity(&quot;myTrigger&quot;, &quot;group1&quot;)
        .startAt(DateBuilder.todayAt(10, 20, 20))
        .withSchedule(CronScheduleBuilder.cronSchedule(&quot;0 &quot; + (min + 1) + &quot; &quot; + hour + &quot; * * ? *&quot;))     
        .build();
         
        // Tell quartz to schedule the job using our trigger
        scheduler.scheduleJob(jobDetail, trigger);
  }
}

huangapple
  • 本文由 发表于 2020年9月1日 15:57:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/63683574.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定