What implementation is used when Autowiring the scheduler interface in Quartz Scheduler? - spring

#Autowired
private Scheduler scheduler;
I found multiple implementations implementing the Scheduler interface (like RemoteScheduler, stdScheduler). So which one is actually being used in Spring?
When I printed out the scheduler class using
scheduler.getClass();
I saw stdScheduler. I'm wondering in what way Quartz is setting up which implementation to use.

Related

Is there any valid reason for declaring a Quartz Job as a spring bean?

By looking at some examples of running quartz jobs in a spring boot app, I see many of them are actually declaring the Job with the #Component annotation :
Baeldung example
Dzone example
Medium example
It seems to be completly useless as the job factory will create a new instance every time the job is triggered.
I can see in my app that the method SpringBeanJobFactory.createJobInstance is called each time the job is executed. I removed the #Component annotation and it works perfectly, so is there any advantage of declaring a Job as a spring bean ?

Mix spring-integration and spring scheduler

We are mixing spring-integration and the scheduling capabilities from spring-boot using:
#SpringBootApplication
#EnableIntegration
#IntegrationComponentScan
#EnableConfigurationProperties
#EnableScheduling
public class MyApplication {
...
}
#EnableScheduling creates a bean named "taskScheduler" which is then used by spring-integration:
public abstract class IntegrationContextUtils {
public static final String TASK_SCHEDULER_BEAN_NAME = "taskScheduler";
...
}
private void registerTaskScheduler() {
if (!this.beanFactory.containsBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME)) {
...
this.registry.registerBeanDefinition(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, scheduler);
}
}
Problem is, the default poolSize for spring-integration is 10 (which value is needed as we encounter starvation) while the default for spring-boot is 1 (which we also need to avoid concurrency in our scheduled processes).
Questions:
Is this a normal behavior for spring-integration to share his task scheduler bean with spring-boot scheduling capabilities?
Is there a way to specify a unique task scheduler for spring-integration, whether scheduling in boot is enabled or not?
Thanks for your answers
The behviour and logic is correct. And expectations from the convention-on-configuration from Spring Boot perspective is also correct. Only what you miss that #EnableScheduling is not a Spring Boot feature, but rather Spring Framework native: https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling. Spring Boot jsut give us an extra freedom of configuration some beans on the matter. So, we just need to rely on its auto-configuration.
If auto-configuration doesn't fit your requirements, you always can provide your own configuration and override whenever it is necessary.
Looking to the #EnableScheduling, its #Scheduled hooks and appropriate TaskSchedulingAutoConfiguration in Spring Boot, it is not so easy to override whatever you want to make Spring Integration happy at the same time. So, we should go a bit opposite direction and really override a Scheduler for Spring Integration endpoints. Every single place where you use poller, you also need to configure a custom Scheduler instead of that auto-configured.

Default TaskExecutor implementation for Async event listeners

I am using an annotation-based event listener which I have also tagged as #Async. (See Asynchronous Listeners).
Which TaskExecutor implementation is Spring using to serve these requests? The documentation reads:
By default, when specifying #Async on a method, the executor that is used is the one configured when enabling async support, i.e. the “annotation-driven” element if you are using XML or your AsyncConfigurer implementation, if any.
The problem is that I haven't done any configuration for this at all, so I am not sure what my AsyncConfigurer implementation is to begin with.
My guess is that we're dealing a SimpleAsyncTaskExecutor.
I found the answer in the documentation for EnableAsync:
By default, Spring will be searching for an associated thread pool definition: either a unique TaskExecutor bean in the context, or an Executor bean named "taskExecutor" otherwise. If neither of the two is resolvable, a SimpleAsyncTaskExecutor will be used to process async method invocations.
So, it's the SimpleAsyncTaskExecutor.

Spring ThreadPoolTaskScheduler vs ThreadPoolTaskExecutor

It is mentioned in the Spring documentation that:
ThreadPoolTaskScheduler actually implements Spring's TaskExecutor interface as well, so that a single instance can be used for asynchronous execution as soon as possible as well as scheduled, and potentially recurring, executions.
So which are the scenarios where we would want to use ThreadPoolTaskExecutor instance over ThreadPoolTaskScheduler instance?
I am using currently using Spring XML. I am creating bean of ThreadPoolTaskScheduler as follows:
<task:scheduler id="myScheduler" pool-size="1"/>
while bean of ThreadPoolTaskExecutor instance can be created as
<task:executor id="executor" pool-size="10"/>
ThreadPoolTaskExecutor is a specialized class for executing tasks.
ThreadPoolTaskScheduler is a specialized class for scheduling tasks.
The sentence you quoted in the Spring documentation is only saying that you can use a scheduler to execute tasks, but that it is not its main purpose. A ThreadPoolTaskExecutor provides fine-grained configuration over the thread pool through its corePoolSize, maxPoolSize, keepAliveSeconds and queueCapacity properties. A scheduler such as ThreadPoolTaskScheduler does not provide such configuration.
As such, choosing between the two comes down the following question: do I need to execute or schedule execution of tasks?

Using Spring AOP with Quartz scheduler

I am using Quartz scheduler for scheduling purposes in my project. I need to gather statistics like when, for how long, and how many times a job was run. I want to use Spring AOP for the same. For this, I am making Job classes spring-managed beans. Spring creates a Proxy class for each of the Job classes. But now when Quartz tries to execute this spring-managed Job, I am getting InstantiationException for the Proxy class created for the Job by Spring.
org.quartz.SchedulerException: Problem instantiating class '$Proxy6'
[See nested exception: java.lang.InstantiationException: $Proxy6]
Can anybody please suggest a solution for this problem?
If you use quarz directly (not via Spring Schedule annotation), you can ask quarz directly for the statistics. -- Many of them are already implemented in quarz.
Because Quartz Job class is managed by Quartz container not Spring container, Spring AOP can not achieve your goal. For your purpose, there are 2 ways that you can work on this:
Quartz has listener mechanism builtin, you can use a global listener to do want you want, as the AOP works. For more information about listener, refer to: Quartz document.
If you insist on Spring AOP, you have to customize the job class instantiation process, so that the job class is managed by Spring Container. One approach is write your own JobFactory, which extends SpringBeanJobFactory then override the createJobInstance() method. If you want more things about this, please comment on this, I will write more detail on this.

Resources