Docker deployment for Spring boot application

Docker deployment of spring boot application is a hot topic in the recent years, here are the detailed steps:Create a spring boot application: start with https://start.spring.io/, select Reactive web and Reactive Mongodb and provide group and artifact, generate project.

Import the generated project into STS (or eclipse)

Spring boot application

package com.leespace.bookstore;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
import org.springframework.core.env.Environment;
import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;

import com.mongodb.ConnectionString;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;

@SpringBootApplication(exclude = { MongoAutoConfiguration.class, MongoDataAutoConfiguration.class })
@EnableReactiveMongoRepositories
@AutoConfigureAfter(EmbeddedMongoAutoConfiguration.class)
public class BookstoreMongoSpringBootApplication extends AbstractReactiveMongoConfiguration {

	
    private final Environment environment;
	 
    public BookstoreMongoSpringBootApplication(Environment environment) {
        this.environment = environment;
    }
	public static void main(String[] args) {
		SpringApplication.run(BookstoreMongoSpringBootApplication.class, args);
	}

	@Override
	public MongoClient reactiveMongoClient() {
		MongoClient mongoClient = MongoClients.create(new ConnectionString(environment.getProperty("spring.data.mongodb.uri")));
		return mongoClient;
	}

	@Override
	protected String getDatabaseName() {
		return "leespacedb";
	}
}

Create Entity class

package com.leespace.bookstore.entity;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import lombok.Data;
import lombok.RequiredArgsConstructor;

@Data
@Document
@RequiredArgsConstructor
public class Product {
	@Id
	private int id;
	private String name;
	private String description;
	private String author;
	private String category;
	private double price;
	private String imageUrl;
	
	public Product(int id, String name, String description, String author, String category, double price,
			String imageUrl) {
		super();
		this.id = id;
		this.name = name;
		this.description = description;
		this.author = author;
		this.category = category;
		this.price = price;
		this.imageUrl = imageUrl;
	}
	
	
}

Create ReactiveRepository

package com.leespace.bookstore.repository;

import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Component;

import com.leespace.bookstore.entity.Product;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Component
public interface ReactiveProductRepository extends ReactiveCrudRepository<Product, String> {
    Flux<Product> findByName(String name);

    Flux<Product> findByName(Mono<String> name);

    Mono<Product> findByNameAndImageUrl(Mono<String> name, String imageUrl);

    @Query("{ 'name': ?0, 'imageUrl': ?1}")
    Mono<Product> findByNameAndImageUrl(String name, String imageUrl);
}

Create RestController

package com.leespace.bookstore.rest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.leespace.bookstore.entity.Product;
import com.leespace.bookstore.repository.ReactiveProductRepository;

import reactor.core.publisher.Flux;

@RestController
public class ProductController {

	@Autowired
	private ReactiveProductRepository propductRepository;

	@GetMapping("/products")
	public Flux<Product> getAllProducts() {
		return propductRepository.findAll();
	}

}

Create Dockerfile

FROM frolvlad/alpine-oraclejdk8:slim
EXPOSE 8080
RUN mkdir -p /app/
ADD target/bookstore-mongo-spring-boot-0.0.1-SNAPSHOT.jar /app/bookstore-mongo-spring-boot.jar
ENTRYPOINT ["java", "-jar", "/app/bookstore-mongo-spring-boot.jar"]

Build docker image

docker build . -t bookstore-mongo-spring-boot

Run spring boot app in a docker container.

Firstly clean up stopped containers: 
docker rm $(docker ps -a -q)
docker run --name="bookstore-mongo-spring-boot-A" --restart unless-stopped --publish 9001:8080 --detach bookstore-mongo-spring-boot 

docker run --name="bookstore-mongo-spring-boot-B" --restart unless-stopped --publish 9002:8080 --detach bookstore-mongo-spring-boot 

You can insert some records in the product collection with the following:

db.product.insert({ “_id” : 1,”name”:”Java”, “description” : “Java introduction”, “author” : “Jack”, “category” : “Book”, “price” : 234, “imageUrl” : “javaUrl”, “_class” : “com.leespace.bookstore.entity.Product”} );

db.product.insert({ “_id” : 2, “name” : “Nodejs”, “description” : “Nodejs introduction”, “author” : “John”, “category” : “Book”, “price” : 134, “imageUrl” : “Nodejsurl” ,”_class” : “com.leespace.bookstore.entity.Product”})

You can check http://localhost:9001/products or http://localhost:9002/products
The expected rest response will be like :

{
"id": 1,
"name": "Java",
"description": "Java introduction",
"author": "Jack",
"category": "Book",
"price": 234,
"imageUrl": "javaUrl"
},
{
"id": 2,
"name": "Nodejs",
"description": "Nodejs introduction",
"author": "steve",
"category": "Book",
"price": 134,
"imageUrl": "Nodejsurl"
}

Read More