Ir al contenido principal

Destacado

Monitoring your micro services with Spring Boot Admin

This new joetip is for those who have in their architecture some micro-services developed with Spring Boot and are already using some Spring Cloud projects such as Spring Cloud Config and Spring Cloud Eureka as Discovery server.

The Spring Boot Admin is a project developed by CodeCentric which is available for free at https://github.com/codecentric/spring-boot-admin so we can monitor our microservices.

In order for these micro-services to be monitored, we have 2 options:


Placing the dependency of spring boot admin client on each projectOr configuring the Eureka (Consul or Zookeeper) so that you can monitor the micro-services that are already registered in it.

I will explain step by step what has to be done to work with the spring boot admin in our microservices cluster. But, if you are impatient and already want to try it, here is the GitHub repository: https://github.com/joedayz/spring-boot-admin-cloud-finchley.

For my demos I will use the following projects and the following versions…

Usando CrudRepository con Kotlin


Ahora vamos a ver si podemos aplicar lo aprendido con Spring Boot y cambiar nuestro código con Kotlin.

Esta vez seguimos con Gradle



Nos aseguramos de tener las siguientes dependencias en buildScript:




buildscript {
 ext {
  kotlinVersion = '1.1.3-2'
  springBootVersion = '1.5.6.RELEASE'
 }
 repositories {
  mavenCentral()
 }
 dependencies {
  classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("org.jetbrains.kotlin:kotlin-noarg:$kotlinVersion")
  classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
  classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
 }
}

El compiler plugin allopen nos evitara estar colocando la palabra reservada open. El compiler plugin noarg agrega un constructor sin argumento donde se encuentre la anotación específica.


// Or "kotlin-jpa" for the Java Persistence API support
apply plugin: "kotlin-noarg"

En nuestro caso usaremos kotlin-jpa para tener un constructor sin argumento en nuestras entidades. Los plugins finalmente serán:


apply {
    plugin("kotlin")
    plugin("kotlin-spring")
    plugin("kotlin-jpa")
    plugin("org.springframework.boot")
}


El plugin kotlin-spring es para poder usar todas las anotaciones de Spring.

Las dependencias del proyecto serán:





dependencies {
 compile('org.springframework.boot:spring-boot-starter-data-jpa')
 compile('org.springframework.boot:spring-boot-starter-web')
 compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:${kotlinVersion}")
 compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
 compile("com.h2database:h2")
 compile("com.fasterxml.jackson.module:jackson-module-kotlin")
 testCompile('org.springframework.boot:spring-boot-starter-test')
}



Nuestra Entidad Alumno

Esta será una entidad JPA. El código es el siguiente:




package com.example.demoCrudRepository

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id

/**
 * Created by josediaz on 7/27/17.
 */
@Entity
class Alumno(
        val firstName: String,
        val lastName: String,
        @Id @GeneratedValue(strategy = GenerationType.AUTO)
        val id: Long = -1) {

    override fun toString(): String {
        return "Alumno(id=$id, firstName='$firstName', lastName='$lastName')"
    }
}

Sobreescribimos el método toString para poder generar un log mas humano. Luego creamos una interface que herede de CrudRepository.


CrudRepository de Spring Data


package com.example.demoCrudRepository

import org.springframework.data.repository.CrudRepository

/**
 * Created by josediaz on 7/27/17.
 */
interface AlumnoRepository : CrudRepository{

    fun findByLastName(lastName: String): Iterable
}


Application con CommandLineRunner

Luego en la clase Application creamos algunos Alumnos y probamos los métodos que Spring Data nos provee con CrudRepository.


package com.example.demoCrudRepository


import org.slf4j.LoggerFactory
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.Bean

@SpringBootApplication
class DemoCrudRepositoryApplication{



        private val log = LoggerFactory.getLogger(DemoCrudRepositoryApplication::class.java)

        @Bean
        fun init(repository: AlumnoRepository) = CommandLineRunner {
            // save a couple of alumnos
            repository.save(Alumno("Elias", "Diaz"))
            repository.save(Alumno("Felipe", "Diaz"))
            repository.save(Alumno("Deborah", "Diaz"))
            repository.save(Alumno("Maria", "Diaz"))
            repository.save(Alumno("Daniel", "Diaz"))

            // fetch all alumnos
            log.info("Alumnos found with findAll():")
            log.info("-------------------------------")
            for (alumno in repository.findAll()) {
                log.info(alumno.toString())
            }
            log.info("")

            // fetch an individual alumno by ID
            val alumno = repository.findOne(1L)
            log.info("Alumno found with findOne(1L):")
            log.info("--------------------------------")
            log.info(alumno.toString())
            log.info("")

            // fetch alumnos by last name
            log.info("Alumno found with findByLastName('Bauer'):")
            log.info("--------------------------------------------")
            for (diaz in repository.findByLastName("Diaz")) {
                log.info(diaz.toString())
            }
            log.info("")
        }


}

fun main(args: Array) {
    SpringApplication.run(DemoCrudRepositoryApplication::class.java, *args)
}




Controller

Finalmente, si queremos usarlo en un Controller.



package com.example.demoCrudRepository;

import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController

@RestController
class AlumnoController(val repository: AlumnoRepository) {

    @GetMapping("/")
    fun findAll() = repository.findAll()

    @GetMapping("/{lastName}")
    fun findByLastName(@PathVariable lastName:String)
            = repository.findByLastName(lastName)


}



Si probamos el resultado es:


Comentarios