Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Building Microservices With Netflix OSS, Apache Kafka, and Spring Boot – Part 3: Email Service and Gateway

DZone's Guide to

Building Microservices With Netflix OSS, Apache Kafka, and Spring Boot – Part 3: Email Service and Gateway

In Part 3 of this series, learn to build an email service configured to listen for the USER_CREATED_TOPIC from the user service.

· Microservices Zone ·
Free Resource

Learn how modern cloud architectures use of microservices has many advantages and enables developers to deliver business software in a CI/CD way.


The next step of building our system is the email service. It will be a microservice configured to listen for the USER_CREATED_TOPIC that comes from the user service. Here we will build a UserDto and configure the Kafka consumer to transform the incoming payload to it. Similarly to the user microservice, here we will have an EmailService where the business logic will be executed. This EmailService will be using the UserDto from the payload, transform it to a Mail entity, save it in the database, and send the mail.

In addition to Eureka Discovery; JPA; H2; Kafka; Config Client; to the new Spring Boot project(ms-mail) in SPRING INITIALIZR, it is necessary to add aMail dependency as well. So the pom.xml looks like:

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.kafka</groupId>
        <artifactId>spring-kafka</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>javax.mail</groupId>
        <artifactId


Sending mail is configured to use Gmail. It is necessary to replace the username and password with real values. This is the mail which will be used as a sender of the confirmation.

/ms-mail.yml

mail:
    host: smtp.gmail.com
    port: 587
    username: username
    password: password
    properties.mail.smtp:
      auth: true
      starttls.enable: true


To be able to read the messages from Kafka, we need to configure ConsumerFactory and wrap KafkaListenerContainerFactory. As well as the ProducerFactory, it needs some configuration properties to be set. @EnableKafka is needed to enable detection of @KafkaListener annotations on any Spring-managed beans.

/ReceiverConfig.java

@Configuration
@EnableKafka
public class ReceiverConfig {

    @Value("${spring.kafka.bootstrap-servers}")
    private String bootstrapServers;

    @Bean
    public Map<String, Object> consumerConfigs() {
        Map<String, Object> props = new HashMap<>();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
        props.put(ConsumerConfig.GROUP_ID_CONFIG, "UserCreatedConsumer");

        return props;
    }

    @Bean
    public ConsumerFactory<String, UserDto> consumerFactory() {
        return new DefaultKafkaConsumerFactory<>(consumerConfigs(), new StringDeserializer(),
                new JsonDeserializer<>(UserDto.class));
    }

    @Bean
    public ConcurrentKafkaListenerContainerFactory<String, UserDto> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, UserDto> factory =
                new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());

        return factory;
    }

    @Bean
    public Receiver receiver() {
        return new Receiver();


Then, in the method annotated with @KafkaListener, we add the logic we want to be invoked when a message is received.

/Receiver.java

private CountDownLatch latch = new CountDownLatch(1);

@KafkaListener(topics = "${spring.kafka.topic.userCreated}")
public void receive(UserDto payload) {
   emailService.sendSimpleMessage(payload);
   latch.countDown();
}


As mentioned above, EmailService is the place where we transform the incoming payload, send the email and save it for future reference.

/EmailServiceImpl.java

public class EmailServiceImpl implements EmailService {

    @Override
    public void sendSimpleMessage(UserDto input) {
        try {

            Mail newMail = new Mail();
            newMail.setTo(input.getUsername());
            newMail.setSubject("TestSubject");
            newMail.setText("TestText");

            SimpleMailMessage message = new SimpleMailMessage();
            message.setTo(newMail.getTo());
            message.setSubject(newMail.getSubject());
            message.setText(newMail.getText());

            mailRepository.save(newMail);
            emailSender.send(message);
        } catch (MailException exception) {
            exception.printStackTrace();
        }
    }
}


To test if everything is fine, build and run the project:

  1. Verify Service registry (Eureka) is running (http://localhost:8761)

  2. Config server (Spring Cloud Config) is running and ms-user and ms-email configuration is available (http://localhost:8888/ms-user/default)

  3. Build the project:  mvn clean install 

  4. Run java-jar ms-mail-0.0.1-SNAPSHOT.jar

  5. Create a new user with the following:

POST http: //localhost:8081/member 
 {
  "username": "email@example.com",
  "password": "password"
 }


    6. Verify user was created: check if an email was received on email@example.com

As you can see from the previous example, to register a user, you should know the details about its service (server IP/port) to query it. Imagine a really complex system with dozens of microservices working together. To solve this we will create a new service(Zuul) that will be the front door for all other microservices. Clients will call this microservice and it will delegate the requests to the appropriate one.

Building Zuul service with Spring Boot is as easy as for the previous microservices. With SPRING INITIALIZR, create a new (ms-gateway) project and Eureka Discovery;Config Client and Zuul dependencies.

/prom.xml

dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>


We configure the microservice Cloud config client:

/bootstrap.yml

server:
  port: 8765
spring:
  application:
    name: ms-gateway
  cloud:
    config:
      discovery:
        enabled: true
        service-id: ms-config-server


Add also @EnableEurekaClient to enable EurekaClient configuration as well for the other microservices. The Zuul functionality is enabled with @EnableZuulProxy annotation in the Application.java file.

Some routing configuration is necessary to be added, for the Zuul to know which request to which service should be redirected. We do this in git config file.

/ms-gateway.yml

zuul:
  routes:
    ms-user: /api/user/**


With this configuration, any request to 8765:/api/user will be redirected to the ms-user microservice. And Zuul will take its address and port from Eureka.

To test if everything is fine, build and run the project:

1. Create new user

POST http: //localhost:8765/api/user/member
 {
  "username": "email@example.com",
  "password": "password"

2. Verify a user was created

GET http://localhost:8765/member

3. Verify an email was sent to 

We saw how to easily build a microservice system which sends emails on registration with Netflix OSS, Apache Kafka, and Spring Boot. The full implementation of these three parts can be found in the GitHub. Feel free to give your comments and give suggestions based on your experience.

Discover how to deploy pre-built sample microservices OR create simple microservices from scratch.

Topics:
integration ,microservices ,apache kafka ,spring boot

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}