How to use #Scheduled annotation in Non-Spring Boot Projects - java

I'm developing a project in Spring without Spring Boot
and I'm not using xml configurations, instead I'm using annotations.
Then how to use #Schedule(cron="bla bla...")
where should I put #EnableScheduling.
Below is my piece of code which is not working:
#RestController
public class MyController {
#Scheduled(cron = "0 40 22 * * SUN")
public void routinessundayBAS1() throws EntityNotFoundException {
System.out.println("coming");
}
}

You need to put #EnableScheduling on any #Configuration class.

As Jakub said, you have to add #EnableScheduling on any #Configuration class. You could configure the scheduler to customize your configuration by implementing the SchedulingConfigurer interface. An example:
#Configuration
#EnableScheduling
#ComponentScan("PACKAGES WITH SCHEDULED ANNOTATIONS")
public class ConfigScheduler implements SchedulingConfigurer {
...
#Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize( threadpoolsize );
scheduler.setThreadGroupName( threadgroupname );
scheduler.setThreadNamePrefix( threadPrefix );
scheduler.setAwaitTerminationSeconds( timeout );
return scheduler;
}
#Override
public void configureTasks(ScheduledTaskRegistrar registrar) {
TaskScheduler scheduler = this.taskScheduler();
registrar.setTaskScheduler( scheduler );
}
...
}

Related

Adding scheduler for #Scheduled annotation in spring without using xml annotations

I have several methods with the annotation #Scheduled. For each annotation or a group of them I want a different scheduler to be used. For example:
Group A has 3 methods with #Scheduled annotation which need to use Scheduler X.
Group B has 5 methods with #Scheduled annotation which need to use Scheduler Y.
From what I have read in Does spring #Scheduled annotated methods runs on different threads?, if the scheduler is not specified then only one of those methods will run at a time.
I know how this connection can be done using xml-based annotation. But is there a way that this can be done using Java-based annotation only?
It can be done using java config. But not using an annotation attributes.
You could have a look at the Spring API doc for some extended example.
For example:
#Configuration
#EnableScheduling
public class AppConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
}
#Bean(destroyMethod="shutdown")
public Executor taskScheduler() {
return Executors.newScheduledThreadPool(42);
}
}
#Scheduled group is not yet supported. See this open issue.
If you want use more than one scheduler you have to create and configure them programmatically. For example:
#Configuration
#EnableScheduling
public class AppConfig implements SchedulingConfigurer {
[...]
#Bean(destroyMethod="shutdown", name = "taskSchedulerA")
public Executor taskSchedulerA() {
return Executors.newScheduledThreadPool(42);
}
#Bean(destroyMethod="shutdown", name = "taskSchedulerB")
public Executor taskSchedulerA() {
return Executors.newScheduledThreadPool(42);
}
}
#Service
public class MyService {
#Autowired #Qualifier("taskSchedulerA")
private Executor taskSchedulerA;
#Autowired #Qualifier("taskSchedulerB")
private Executor taskSchedulerB;
#PostConstruct
public void schedule(){
Executors.newScheduledThreadPool(42).schedule(new Runnable() {
#Override
public void run() {
functionOfGroupA();
}
} , ..);
}
}

Where should I put #EnableAsync annotation

I need to send a email in async way while saving the data into DB.
My approach was like this.
//I have tried with service layer annotating.But not worked.
#EnableAsync
class MyService{
public String saveMethod(List listOfData){
mail.sendEmailQuote(listOfData);
mail.sendEmailWorkflowTaskAssignment(listOfData);
myDao.saveData(listOfData);
}
}
I need to perform following methods in #Async way. Where should I put #EnableAsync annotation. This is not a Schedule related thing. This is happen when user click save button. Application is used flex spring blazeDS. There is no controller written by my self.
I have used #Async annotation in my code for following 2 methods. Those are in class call Mail.
#Async
sendEmailQuote(listOfData){}
#Async
sendEmailWorkflowTaskAssignment(listOfData){}
Could you help me to find where should I put #EnableAsync ?
I refer this sample
EnableAsync is used for configuration and enable Spring's asynchronous method execution capability, it should not be put on your Service or Component class, it should be put on your Configuration class like:
#Configuration
#EnableAsync
public class AppConfig {
}
Or with more configuration of your AsyncExecutor like:
#Configuration
#EnableAsync
public class AppConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return executor;
}
}
Please refer to it's java doc for more details.
And for the tutorial you followed, EnableAsync is put above Application class, which extends AsyncConfigurerSupport with AsyncExecutor configuration:
#SpringBootApplication
#EnableAsync
public class Application extends AsyncConfigurerSupport {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("GithubLookup-");
executor.initialize();
return executor;
}
}
Just make sure that #Async methods aren't called by the same class. Self invocation for proxy won't work.

Spring Async ThreadPoolTaskScheduler not initialized

I'm trying to use Async annotation in Spring but I'm getting
java.lang.IllegalStateException: ThreadPoolTaskScheduler not initialized
error, when I try to run the method marked as Async. The following is the configuration for Async:
#EnableScheduling
#EnableAsync
#Configuration
public class SchedulingConfiguration implements AsyncConfigurer{
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(10);
return scheduler;
}
}
and the following is the declaration of async method.
#Async
#Transactional(value = "baseTransactionManager", isolation = Isolation.READ_COMMITTED)
public void foo(Bar bar) {// some code here}
What am I missing in here?
Thanks in advance.
You have to explicitly call scheduler.initialize() after setting all properties but before returning the scheduler.
See full working test case here.

Why Spring Boot Batch job is running just one time?

I'm using spring boot. I have a batch job which I've implemented with these classes :
My main class is :
#SpringBootApplication
#ComponentScan("com.batch")
#PropertySource("classpath:application.properties")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
My scheduler is :
#Component
#EnableScheduling
public class JobScheduler {
#Scheduled(fixedRate = 10000)
public void runJob() {
SpringApplication.run(MyBatchConfig.class);
}
}
and my batch configuration class is :
#Configuration
#EnableBatchProcessing
public class MyBatchConfig {
#Value("${database.driver}")
private String databaseDriver;
#Value("${database.url}")
private String databaseUrl;
#Value("${database.username}")
private String databaseUsername;
#Value("${database.password}")
private String databasePassword;
#Bean
public Job myJob(JobBuilderFactory jobs, Step s) {
Job job = jobs.get("myJob")
.incrementer(new RunIdIncrementer())
.flow(s)
.end()
.build();
return job;
}
#Bean
public Step myStep(StepBuilderFactory stepBuilderFactory, ItemReader<Account> reader,
ItemWriter<Person> writer, ItemProcessor<Account, Person> processor) {
TaskletStep step = stepBuilderFactory.get("myStep")
.<Account, Person>chunk(1)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
step.setAllowStartIfComplete(true);
return step;
} ...
now, my problem is :
the scheduler works and it repeats every ten seconds,
but the job executes only on application startup(reader, processor and writer just execute once in startup) and it seems that
SpringApplication.run(MyBatchConfig.class);
has no effect on re-running the job.
what should I do?
Thanks in advance
This is what I can think of,
1.You put this property in application.properties so your batch job doesn't start automatically by call of SpringApplication.run(...) from mainmethod.
spring.batch.job.enabled=false
This will simply initialize your Spring Batch configuration and not actually start job.
2.Put annotation #EnableScheduling on your Spring Boot Batch Job starting class i.e. on Application class in your code.
3.Remove #EnableScheduling annotation from JobScheduler class and call , jobLauncher.run(job, jobParameters) from runJob() instead of calling SpringApplication.run(MyBatchConfig.class).
JobLauncher & Job beans can be auto wired to your scheduler class since context is already initialized.
Hope it helps !!
You need to create JobLauncher bean and use that in scheduler for starting new job instances.

Spring-MVC + Spring-websocket + #Cacheable don't work

I have got a project on Spring-MVC and Spring-websockets and I try to plug cache on my service layer. These are my configuration:
#Configuration
#ComponentScan(basePackages = {
"com.example"
})
#PropertySource("classpath:/configuration.properties")
#EnableWebMvc
#EnableAspectJAutoProxy(proxyTargetClass = true)
#EnableCaching
public class WebAppConfig extends WebMvcConfigurerAdapter {
#Bean
public EhCacheManagerFactoryBean ehcache() {
EhCacheManagerFactoryBean ehCache = new EhCacheManagerFactoryBean();
ehCache.setConfigLocation(new ClassPathResource("ehcache.xml"));
ehCache.setShared(true);
return ehCache;
}
#Bean
public CacheManager cacheManager() {
return new EhCacheCacheManager(ehcache().getObject());
}
//...different settings by mvc
}
and my websocket configuration:
#Configuration
#EnableAsync
#EnableWebSocket
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue/", "/topic/");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/locations").withSockJS();
}
#Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(4).maxPoolSize(10);
}
}
I want to use #Cacheable annotation on my service layer:
#Service
public class StoreServiceImpl implements StoreService {
private static final Log logger = LogFactory.getLog(StoreServiceImpl.class);
#Autowired
private StoreRepository storeRepository;
#Override
#Cacheable("stores")
public Store findById(String storeId) {
return storeRepository.findById(storeId);
}
//... others methods
}
but if I have included annotation #EnableWebSocketMessageBroker then the cache doesn't work, because aop interceptors do not use it, so
if I haven't included #EnableWebSocketMessageBroker then cache and AOP interceptors work well.
The documentation on the websocket I found this information:
In some cases a controller may need to be decorated with an AOP proxy
at runtime. One example is if you choose to have #Transactional
annotations directly on the controller. When this is the case, for
controllers specifically, we recommend using class-based proxying.
This is typically the default choice with controllers. However if a
controller must implement an interface that is not a Spring Context
callback (e.g. InitializingBean, *Aware, etc), you may need to
explicitly configure class-based proxying. For example with
<tx:annotation-driven />, change to <tx:annotation-driven proxy-target-class="true" />
I tried use #EnableCaching(proxyTargetClass = true), but it didn't help.
Has anyone encountered this problem?
I decided this problem:
I changed mode in #EnableAsync(mode = AdviceMode.ASPECTJ) and it works.
I think it depends of the order initialization BeanPostProcessors

Categories