Published on

Spring, Spring Boot And Jenkins

Authors
  • avatar
    Name
    Me
    Twitter

Introduction

Usually when I'm browsing applications and projects, Spring and Spring Boot is brought up in the list of established requirements, or as components in the current tech stack. Normally I would find these in a fullstack context, since this is the domain I usually look within. However, I wasn't sure if it was frontend related or backend related, which in turn spiked my curiosity to learn more about it.

So what is Spring, and Spring Boot?

Ingame Screenshot

Description

First let's start with Spring. Spring is a application framework designed to be a comprehensive and versatile platform for enterprise Java development. At it's core, it uses the concept of Inversion of Control (IoC) and Dependency Injection (DI) to help promote an easier to maintain and test codebase.

Spring Boot on the other hand is more of a convinience framework that "makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run"". It brings a lot of autoconfiguration, and helps reduce boilerplate coding.

Frontend? Backend?

In a sense, the Spring framework helps promote more scalable development in bigger projects, but still retains similar use cases of normal Java projects. This is my understanding of it at least. Java can be used for pretty much everything, but isn't necessarily used for web development in replacement of something like React. In a similar way i think Spring is used mostly in a backend context, rather than a frontend one.

To learn more about it, I decided to try it out myself by creating a Spring project. I also wanted to learn more about Jenkins, so I integrated this as well into the exercise.

Design

Ingame Screenshot

Code

A lot of time was spent trying to decide on a good project structure. Ultimately I settled on packaging based on layers, so things like services and controllers get their own package. Here is how my tree ended up looking in the end:

Ingame Screenshot

The project was connected to my own MongoDB cluster, where it fetched data for my previous project "känslobarometern" (see previous projects). I then later used it as a alternative API server for my känslobarometer project, to fetch database values.

Testing

Unit testing in particular is something I don't get to work with a whole lot, but is especially convenient with Spring and Spring Boot. Using annotations like @MockBean allows the user to easily mock the functionality of let's say a repository. Heres an example of me using the @MockBean annotation in my own project:

    @MockBean
    private PetRepository petRepository;

    ...

    @Test
    public void shouldReturnPersonalizedPetMessage() throws Exception {
        Pet mockPet = new Pet("Kom", "Bo");
        when(petRepository.findByName("Kom")).thenReturn(mockPet);

Here we are using a mock repository, rather than the real thing.

@Autowired is another annotation that allows Spring to automatically inject dependencies into the class (DI). In this project for example, I used it to easily inject any dependencies for MockMvc.


    @Autowired
    private MockMvc mockMvc;

    ...

    @Test
    public void shouldReturnPersonalizedMessage() throws Exception {
        mockMvc.perform(get("/greeting?name=John")
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.content", is("Hello this is a test commit, John!")));
    }

In a similar way to MockBean, MockMvc seeks to mock the mvc controller instead.

CI/CD (Jenkins)

The process of integration and deployment of the Spring Boot App is as follows:

  1. Code gets deployed to github
  2. SCM polling from Jenkins picks up new commit, and starts pipeline
  3. Pipeline uses included Jenkinsfile to build and push image to Docker Hub
  4. Azure Service App picks up on Docker Hub updating, and deploys new image

The Jenkins server was self deployed by me, using our company OpenStack environment. Here is the contents of the Jenkinsfile:

pipeline {
    agent any

    stages {

        stage('Clone repository') {
            steps {
                checkout scm
            }
        }

        stage('Build') {
            steps {
                sh 'chmod +x complete/gradlew'
                sh 'cd complete && ./gradlew build'
            }
        }

        stage('Build image') {
            steps {
                script {
                    app = docker.build("valkeh/spring", "complete/")
                }
            }
        }

        stage('Test image') {
            steps {
                script {
                    app.inside {
                        sh 'echo "Tests passed"'
                    }
                }
            }
        }

        stage('Push image') {
            steps {
                script {
                    docker.withRegistry('https://registry.hub.docker.com', 'docker-hub-credentials') {
                        app.push("${env.BUILD_NUMBER}")
                        app.push("latest")
                    }
                }
            }
        }
    }
}

Spring Boot Project (ask for access): https://github.com/valkehh/spring-boot-mongodb