How to run Scheduled task after specific CommandLineRunner? - spring

I do some initializations in a CommandLineRunner's run function and I want my Scheduled task to begin schedule after the initialization, how can I achive this?
For example, I have the CommandLineRunner:
#Component
public class MyCommandLineRunner implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
// Initializations
// ...
}
}
And the task scheduler:
public class SchedClass {
#Scheduled(fixedRate = ONE_SECOND)
public void sched() {
}
}
What can I do to make sched() runs after run() runs?

class MySchedulingConfigurer implements SchedulingConfigurer {
private ScheduledTaskRegistrar taskRegistrar;
private IntervalTask task;
public MySchedulingConfigurer(IntervalTask task) {
this.task = task;
}
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
this.taskRegistrar = taskRegistrar;
}
public void resume() {
this.taskRegistrar.scheduleFixedRateTask(task);
}
}
#Configuration
class SchedulerConfiguration {
#Autowired
private MySchedulingConfigurer schedulingConfigurer;
#Bean
public MySchedulingConfigurer mySchedulingConfigurer() {
IntervalTask task = new IntervalTask(new MyTask(), 5000L);
return new MySchedulingConfigurer(task);
}
public static class MyTask implements Runnable {
#Override
public void run() {
System.out.println("===> task executed...");
}
}
#EventListener
public void startScheduler(ApplicationReadyEvent event){
schedulingConfigurer.resume();
}
}
#Component
class CacheLoadingRunner implements CommandLineRunner {
#Autowired
private MySchedulingConfigurer schedulingConfigurer;
#Override
public void run(String... args) throws Exception {
schedulingConfigurer.resume();
}
}

1) Add #EnableScheduling
#EnableScheduling
#SpringBootApplication
public class MyCommandLineRunner implements CommandLineRunner {
...
}
2) It makes no sense to denote Spring Boot application with #Component
UPDATED
It could be achieved manually. Provide a TaskScheduler
#Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(5);
threadPoolTaskScheduler.setThreadNamePrefix("ThreadPoolTaskScheduler");
return threadPoolTaskScheduler;
}
Inject it into MyCommandLineRunner along with SchedClass and run
#Component
public class MyCommandLineRunner implements CommandLineRunner {
#Autowired
private ThreadPoolTaskScheduler taskScheduler;
#Autowired
private SchedClass schedBean;
#Override
public void run(String... args) throws Exception {
// ...
taskScheduler.scheduleWithFixedDelay(() -> schedBean.sched(), ONE_SECOND);
// ...
}
}

Related

How to use Spring boot AutoWired and ScheduledExecutorService?

I need to use autowired in more than one class with ScheduledExecutorService, what I have tried is shown in this code. logging size of User list in below example always shows 0, even after user added to arraylist. How to properly use Autowired and ScheduledExecutorService in spring boot?
#Component
public class AnotherClass {
List<User> users = new ArrayList();
public void addUser(User user){
users.add(user);
}
public void logUsers(){
logger.info("User size " + users.size()); <================= Always logs 0, when called from executor
}
}
#RestController
public class SecondClass {
#Autowired
private AnotherClass anotherClass;
#GetMapping(value="/user/test")
public void logUsers(){
anotherClass.addUser(new User());
}
}
Application Class
#Component
#SpringBootApplication
public class SpringBootDemoApplication {
private ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
#Autowired
private AnotherClass anotherClass;
#PostConstruct
public void init() {
logger();
}
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
public void logger(){
exec.scheduleAtFixedRate(new Runnable(){
#Override
public void run(){
try {
anotherClass.logUsers();
}catch (Exception e){
}
}
}, 2000, 1000, TimeUnit.MILLISECONDS);
}
}
The code works if you use the Spring #Autowired and not the #AutoWired Annotation.

How to use threadPoolExecutor for async spring

I have a requirement to use same thread for multiple request in async spring.
Here is the code which i am using :
Here is the Executor configuration file
#Configuration
#EnableAsync
public class ExecutorConfig {
#Bean(name = "threadPoolExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("threadPoolExecutor-");
executor.initialize();
return executor;
}
}
Here is the service file
public interface QueueService {
public void createQueue();
public void sendData();
}
Here is the Service Implementation
#Service
public class QueueServiceImpl implements QueueService {
#Override
#Async("threadPoolExecutor")
public void createQueue() {
System.out.println(Thread.currentThread().getName());
}
#Override
#Async("threadPoolExecutor")
public void sendData() {
// Need to use the same thread which created the queue
// Thread.currentThread() should be same for both methods
System.out.println(Thread.currentThread().getName());
}
}
Here is the controller class
#RestController
public class Controller {
#Autowired
QueueService queueService;
#RequestMapping(value="/create", method = RequestMethod.GET)
public void createQueue()
{
queueService.createQueue();
}
#RequestMapping(value="/send", method = RequestMethod.GET)
public void sendDataToQueue()
{
queueService.sendData();
}
}
Here is the Spring boot main application
#EnableAsync
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Please let me know how to use #Async in 2 separate request to do the job done by same thread.

execute spring job with scheduler except holidays

I have a java job configured with #EnableScheduling and I am able to run job with annotation
#Scheduled(cron = "${job1.outgoingCron:0 45 15,18,20 * * MON-FRI}", zone = "America/New_York")
public void Process() {
}
But I don't want to run this job for US holidays what is the best way to update schedule.
Try to set your schedule explicitly, using CronTrigger or custom Trigger, for example:
#SpringBootApplication
#EnableScheduling
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Bean
public TaskScheduler taskScheduler() {
return new ThreadPoolTaskScheduler();
}
}
#Component
#RequiredArgsConstructor // Lombok annotation
public class StartUp implements ApplicationRunner {
#NonNull private final TaskScheduler scheduler;
#Override
public void run(ApplicationArguments args) throws Exception {
// Variant 1
scheduler.schedule(this::myTask, new CronTrigger(/* your schedule */));
// Variant 2
scheduler.schedule(this::myTask, this::myTriger);
}
private void myTask() {
//...
}
private Date myTrigger(TriggerContext triggerContext) {
//...
}
}

Spring - access #Autowired service from AbstractMessageHandler

I have a SpringBootApplication which subscribes to MQTT broker. MQTT messages need to be saved to Database, but I cannot access my #Autowired service.
Exception I get:
Field deviceService in com.example.MqttMessageHandler required a bean of type 'com.example.service.DeviceService' that could not be found.
MQTTApiApplication.java
#SpringBootApplication(scanBasePackages = "{com.example}")
public class MQTTApiApplication {
public static void main(String[] args) {
SpringApplicationBuilder(MQTTApiApplication.class)
.web(false).run(args);
}
#Bean
public IntegrationFlow mqttInFlow() {
return IntegrationFlows.from(mqttInbound())
.handle(new MqttMessageHandler())
.get();
}
}
MqttMessageHandler.java
public class MqttMessageHandler extends AbstractMessageHandler {
#Autowired
DeviceService deviceService;
#Override
protected void handleMessageInternal(Message<?> message) throws Exception {
deviceService.saveDevice(new Device());
}
}
Application.java
#SpringBootApplication
public class MQTTApiApplication {
public static void main(String[] args) {
SpringApplication.run(MQTTApiApplication.class, args);
}
#Bean
public IntegrationFlow mqttinFlow(MqttMessageHandler handler) {
return IntegrationFlows
.from(mqttInbound())
.handle(handler).get();
}
}
MqqtMessageHandler.java
#Component
public class MqttMessageHandler extends AbstractMessageHandler{
#Autowired
private DeviceService deviceService;
#Override
protected void handleMessageInternal(String message) {
//...
}
}
DeviceService.java
#Service
public class DeviceService {
#Autowired
private DeviceRepository repository;
//...
}
DeviceController.java
#RestController
#RequestMapping("/")
public class DeviceController {
#Autowired
private IntegrationFlow flow;
//...
}
DeviceRepository.java
#Repository
public class DeviceRepository {
public void save() {
//...
}
}

Spring Boot + DynamoDBTypeConverter dependancy injection

I'm trying to get DI working with a sample DynamoDBTypeConverter I'm playing around with and having no luck at all :( My service is always null and throws an error as a result in my jUnit test.
Here's my converter:
#Component
public class ArmTypeConverter implements DynamoDBTypeConverter<String, Arm> {
#Autowired
private ArmRepository armRepository;
#Override
public String convert(Arm Arm) {
return arm.getId();
}
#Override
public Arm unconvert(String id) {
return armRepository.findOne(id);
}
}
My application main:
#SpringBootApplication
#ComponentScan
#EnableSpringConfigured
#EnableLoadTimeWeaving(aspectjWeaving=EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
#EnableAutoConfiguration
public class ArmApplication implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(ArmApplication.class, args);
}
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() throws Throwable {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
}
My service:
#Service
public class ArmServiceImpl implements ArmService {
#Autowired
private ArmRepository armRepository;
#Override
public Arm create(String length, Set<Register> registers) {
Date now = new Date();
Arm arm = new Arm();
arm.setLength("85cm");
return armRepository.save(arm);
}
}
My Test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class ArmServiceTests {
#Autowired
private ArmService armService;
#Autowired
private TorsoService torsoService;
private Arm arm;
#Before
public void before() {
arm = armService.create("85cm", null);
torsoService.create("150cm", arm);
}
#After
public void after() {
// do nothing for now...
}
#Test
#WithUserDetails("admin#somewhere.com")
public void getArmTest() {
Arm c = armService.getArm(arm.getId());
assertThat(c).isNotNull();
assertThat(c.getId()).isEqualTo(arm.getId());
}
}
What am I doing wrong?
The issue was that I didn't have load time weaving configured properly

Resources