Reputation: 5482
I am using Dagger 2 as my DI framework and I am providing a singleton class instance with it.
I also use Quartz Scheduler to schedule jobs. Is there any way to inject the singleton class into the Quartz job?
Dagger 2 module:
@Module
public class MyModule {
@Provides
@Singleton
Messager provideMessager() {
return new CustomMessager();
}
}
Dagger 2 component:
@Component(modules = MyModule.class)
@Singleton
public interface MyComponent {
Messager messager();
}
Quartz Job:
public class MyJob implements Job {
// @Inject
Messager messager;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
messager.sendMessage("Hello.");
}
}
EDIT
I have created a MyJobScheduler
class that calls the Quartz Job:
public class MyJobScheduler {
public void scheduleJob() {
JobDetail myJob = JobBuilder.newJob(MyJob.class)
.withIdentity("myJobId", "Group1")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTriggerId", "Group1")
.startNow()
.build();
Scheduler scheduler = new org.quartz.impl.StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(myJob, trigger);
}
}
EDIT 2
So I managed to configure it to work, but I don't know if this is the correct approach.
First I created a DependencyResolver
class, which I use as a singleton:
public class DependencyResolver {
private static DependencyResolver _instance = null;
private static MyComponent _myComponent;
public static MyComponent getMyComponent() {
return _myComponent;
}
protected DependencyResolver() {
// Exists only to defeat instantiation.
}
public static void initialize() {
_myComponent = DaggerMyComponent.builder().build();
}
}
Then I called the initialize method in the main
method:
DependencyResolver.initialize();
MyComponent myComponent = DependencyResolver.getMyComponent();
And I used the DependencyResolver
in MyJob class to get the Messager
singleton instance.
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
MyComponent myComponent = DependencyResolver.getMyComponent();
Messager messager = myComponent.messager();
messager.sendMessage("Hello.");
}
}
Is this the correct way to solve this issue? Any input will be greatly appreciated.
Upvotes: 4
Views: 4381
Reputation: 3679
Your EDIT 2 DependencyResolver
approach kind of defeats the whole reason to use Dagger to inject the dependencies, because your job gets the dependency from a singleton provider. :-) It completely bypasses the benefit of Dagger, so you might as well just have a singleton on the source dependency itself, like: Messager messager = CustomMessager.getInstance()
or something like that.
One reason to use Dependency Injection, is to assist with unit testing, and in this case you're losing the ability to mock your Messager implementation in a unit test.
The proper way to use dependency injection with Quartz jobs is mentioned in the API doc for JobFactory: "This interface may be of use to those wishing to have their application produce Job instances via some special mechanism, such as to give the opertunity for dependency injection."
The trick is to create your own job factory that extends SimpleJobFactory
and then you have an opportunity to initialize/inject the job's dependencies, something like this:
public class MyJobFactory extends SimpleJobFactory {
private final MyComponent component;
@Inject
public MyJobFactory(MyComponent component) {
this.component = component;
}
@Override
public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
final Job job = super.newJob(bundle, scheduler);
if (job instanceof MyJob) {
component.inject((MyJob) job);
}
return job;
}
}
And then you tell the scheduler to use your job factory:
scheduler.setJobFactory(myJobFactory);
See the full code here on GitHub
Upvotes: 6