Java @ Desk: SpringBoot | Java at your desk

Implement Scheduler in Spring Boot

Implement Scheduler in Spring Boot

Scheduler is implemented in Spring Boot using org.springframework.scheduling.annotation.Scheduled annotation. It takes input as a cron expression along with the time zone.

The @Scheduled annotation is used with a method that performs specific tasks at regular intervals. The package of the scheduler class need to be provided in the Spring Boot main application using scanBasePackages property. During deployment, Spring scans the component provided in scanBasePackages and schedules based on cron provided in scheduler class.

Here is the sample code for the same.
import java.time.LocalDateTime;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class MyScheduler {

 final Logger logger = LoggerFactory.getLogger(MyScheduler.class);

 /* scheduled to run at every 5 minutes */
 @Scheduled(cron = "0 0/5 * * * *", zone = "Asia/Calcutta")
 public void run() {
  logger.debug("Scheduler Service Started at " + LocalDateTime.now());
 }

}


Spring Boot Main class
The main class must provide below annotation along with scanBasePackages.
@SpringBootApplication(scanBasePackages = { "com.scheduler" })

Spring Boot Messaging Queue RabbitMQ using AMQP

Spring Boot RabbitMQ using AMQP

Below example configures the messaging queue between the sender and the listener. In the example, the scheduler sends the message to the queue every 3 seconds which will be pulled by the Listener class.

The implementation is in the Spring Boot.

AMQP is a protocol that defines communication between systems.

Project Setup
1) pom.xml - Defines the entry for Spring Boot AMPQ library
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-amqp</artifactId>
 <version>1.5.4.RELEASE</version>
</dependency>


2) Sender.java - This class uses a scheduler implementation that pushes the message into the queue every 3 seconds. RabbitTemplate class helps sending the message to the Listener. It pushes the message into the queue.
package com.accenture.springmessage;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
public class Sender {

 @Autowired
 private final RabbitTemplate rabbitTemplate;

 @Autowired
 public StoryEnsRequestSender(final RabbitTemplate rabbitTemplate) {
  this.rabbitTemplate = rabbitTemplate;
 }

 @Scheduled(fixedDelay = 3000L)
 public void sendMessage() {
  String message = "Hello";
  System.out.println("Send Message - " + message);
  rabbitTemplate.convertAndSend(App.EXCHANGE_NAME, App.ROUTING_KEY, message);
 }
}


3) Listener.java - This class uses the @RabbitListener annotation that fetches the message from the queue. The queue is identified using the queue names attribute.
package com.accenture.springmessage;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

@Service
public class Listener {

 @RabbitListener(queues = App.QUEUE_SPECIFIC_NAME)
 public void receiveMessage(final String customMessage) {
  System.out.println("Received message - " + customMessage.toString());
 }
}


4) App.java - Configuration class to define the queue name, exchange name and routing key. Class must implement RabbitListenerConfigurer and below annotations are used @SpringBootApplication, @EnableScheduling, @EnableRabbit.
Enable Rabbit annnotation is used to enable the rabbit configuration.
Enable Scheduling pushes the message in the queue every 3 seconds.


package com.accenture.springmessage;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 * Hello world!
 *
 */
@SpringBootApplication
@EnableScheduling
@EnableRabbit
public class App implements RabbitListenerConfigurer {
 public static void main(String[] args) throws InterruptedException {
  SpringApplication.run(App.class, args);
 }

 public static final String EXCHANGE_NAME = "appExchange";
 public static final String QUEUE_SPECIFIC_NAME = "appSpecificQueue";
 public static final String ROUTING_KEY = "messages.key";

 @Bean
 public TopicExchange appExchange() {
  return new TopicExchange(EXCHANGE_NAME);
 }

 @Bean
 public Queue appQueueSpecific() {
  return new Queue(QUEUE_SPECIFIC_NAME);
 }

 @Bean
 public Binding declareBindingSpecific() {
  return BindingBuilder.bind(appQueueSpecific()).to(appExchange()).with(ROUTING_KEY);
 }

 @Bean
 public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
  final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
  rabbitTemplate.setMessageConverter(producerJackson2MessageConverter());
  return rabbitTemplate;
 }

 @Bean
 public Jackson2JsonMessageConverter producerJackson2MessageConverter() {
  return new Jackson2JsonMessageConverter();
 }

 @Bean
 public MappingJackson2MessageConverter consumerJackson2MessageConverter() {
  return new MappingJackson2MessageConverter();
 }

 @Bean
 public DefaultMessageHandlerMethodFactory messageHandlerMethodFactory() {
  DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
  factory.setMessageConverter(consumerJackson2MessageConverter());
  return factory;
 }

 @Override
 public void configureRabbitListeners(final RabbitListenerEndpointRegistrar registrar) {
  registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory());
 }
}


5) Output

Send Message - Hello at - Tue Jun 27 19:50:22 IST 2017
Received message - Hello at - Tue Jun 27 19:50:22 IST 2017
Send Message - Hello at - Tue Jun 27 19:50:25 IST 2017
Received message - Hello at - Tue Jun 27 19:50:25 IST 2017
Send Message - Hello at - Tue Jun 27 19:50:28 IST 2017
Received message - Hello at - Tue Jun 27 19:50:28 IST 2017
Send Message - Hello at - Tue Jun 27 19:50:31 IST 2017
Received message - Hello at - Tue Jun 27 19:50:31 IST 2017
Send Message - Hello at - Tue Jun 27 19:50:34 IST 2017
Received message - Hello at - Tue Jun 27 19:50:34 IST 2017

Spring Boot with Mongo DB example

Spring Boot with Mongo DB example

This example demonstrates the integration of Mongo DB with Spring Boot. If you are running Mongo DB locally, then there is no need to configure anything for the Mongo database in the spring boot application.

Spring boot auto configures the mongo db configuration since by default mongo runs on
1) host - localhost or 127.0.0.1
2) port - 27017

If you are running a mongo db on local system, then you just have to configure the mongo repository interface in your spring boot application and use @EnableMongoRepositories annotation. Once you run the spring boot application you will notice a following log in your mongo db command prompt
connection accepted from 127.0.0.1:52994 #1 (1 connection now open)

This indicates that the spring boot application is connected to mongo db and you can perform db operations.

And once you stop the application you will observe
end connection 127.0.0.1:52994 (1 connection now open)


In any case there is a need for configuring the change in host or port, then perform following changes in application.properties file
server.port=8070
spring.dao.exceptiontranslation.enabled=false
spring.data.mongodb.host=127.0.0.1
spring.data.mongodb.port=27017


Here is the maven dependency for spring data for mongo db
<dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-mongodb</artifactId>
 <version>1.10.1.RELEASE</version>
</dependency>


Spring Boot app java class - This class configures the spring controller file plus enables the mongo repository using @EnableMongoRepositories annotation.
package com.springbootservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

import com.repository.AppRepository;

@SpringBootApplication(scanBasePackages = { "com.controller"})
@EnableMongoRepositories(basePackageClasses = AppRepository.class)
public class App {

 public static void main(String[] args) {
  SpringApplication.run(App.class, args);
 }
}




Repository Interface - Mongo comes with the MongoRepository interface that internally performs all the basic db operations like insert, get & delete on its own. You must have to create a repository interface that extends MongoRepository interface along with the type. If you have mongo db data object Person then MongoRepository enables all basic operations on Person object.
package com.repository;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

import com.model.Person;

@Repository()
public interface AppRepository extends MongoRepository<Person, String> {

}


Mongo Model class
package com.model;

import org.springframework.data.annotation.Id;

public class Person {
 @Id
 private String id;

 private String name;

 public String getId() {
  return id;
 }

 public void setId(String id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

}


Test Controller - Simply autowire the AppRepository object and start performing DB operations as shown below
@Autowired
private AppRepository appRepository;

@RequestMapping(method = RequestMethod.GET, path = "/test/Mongo", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> getTest() {
 String temp = "abc";
 Person person = new Person();
 person.setId("Id");
 person.setName("Kumar");
 appRepository.insert(person);

 Person person2 = appRepository.findOne("Id");
 System.out.println("Person - " + person2);
 System.out.println(person2.getName());
 appRepository.delete("Id");
 System.out.println("Deleted Successfully");
 return new ResponseEntity<String>(temp, HttpStatus.OK);

}