1. Vue d’ensemble

Actionneur de botte de printemps

1. Vue d'ensemble

Dans cet article, nous allons vous présenter Spring Boot Actuator. We’ll cover the basics first, then discuss in detail what’s available in Spring Boot 1.x vs 2.x.

Nous allons apprendre à utiliser, configurer et étendre cet outil de surveillance dans Spring Boot 1.x. Ensuite, nous verrons comment faire de même avec Boot 2.x et WebFlux en tirant parti du modèle de programmation réactive.

Spring Boot Actuator est disponible depuis avril 2014, en même temps que la première version de Spring Boot.

Avec lesrelease of Spring Boot 2, l'actionneur a été repensé et de nouveaux points de terminaison intéressants ont été ajoutés.

Ce guide est divisé en 3 sections principales:

Lectures complémentaires:

Configurer une application Web Spring Boot

Certaines des configurations les plus utiles pour une application Spring Boot.

Read more

Création d'un démarreur personnalisé avec démarrage à ressort

Un guide rapide et pratique pour créer des démarreurs Spring Boot personnalisés.

Read more

Test en démarrage de printemps

Découvrez comment Spring Boot prend en charge les tests pour écrire efficacement des tests unitaires.

Read more

2. Qu'est-ce qu'un actionneur?

Essentiellement, Actuator apporte des fonctionnalités prêtes à la production à notre application.

Surveiller notre application, collecter des métriques, comprendre le trafic ou l'état de notre base de données devient trivial avec cette dépendance.

Le principal avantage de cette bibliothèque est que nous pouvons obtenir des outils de production sans avoir à implémenter ces fonctionnalités nous-mêmes.

L'actionneur est principalement utilisé pourexpose operational information about the running application - santé, métriques, info, vidage, env, etc. Il utilise des points de terminaison HTTP ou des beans JMX pour nous permettre d’interagir avec lui.

Une fois que cette dépendance est sur le chemin de classe, plusieurs points de terminaison sont disponibles immédiatement. Comme avec la plupart des modules Spring, nous pouvons facilement le configurer ou l'étendre de nombreuses manières.

2.1. Commencer

Pour activer Spring Boot Actuator, nous devons simplement ajouter la dépendancespring-boot-actuator à notre gestionnaire de packages. En Maven:


    org.springframework.boot
    spring-boot-starter-actuator

Notez que cela reste valable quelle que soit la version de démarrage, car les versions sont spécifiées dans la nomenclature de démarrage du printemps.

3. Actionneur Spring Boot 1.x

Dans 1.x, Actuator suit un modèle R / W, cela signifie que nous pouvons le lire ou lui écrire. E.g. nous pouvons récupérer des métriques ou la santé de notre application. Alternativement, nous pourrions mettre fin à notre application ou changer notre configuration de journalisation.

Pour que cela fonctionne, Actuator exige que Spring MVC expose ses points de terminaison via HTTP. Aucune autre technologie n'est prise en charge.

3.1. Points de terminaison

Dans 1.x, Actuator apporte son propre modèle de sécurité. Il tire parti des constructions Spring Security, mais doit être configuré indépendamment du reste de l'application.

En outre, la plupart des points de terminaison sont sensibles - ce qui signifie qu'ils ne sont pas entièrement publics, ou en d'autres termes, la plupart des informations seront omises - alors qu'une poignée ne l'est pas, par exemple. /info.

Voici quelques-uns des points finaux les plus courants fournis par Boot:

  • /health - Affiche les informations de santé de l'application (un simple‘status' lors d'un accès via une connexion non authentifiée ou les détails complets du message lors de l'authentification); il n’est pas sensible par défaut

  • /info – Affiche des informations d'application arbitraires; pas sensible par défaut

  • /metrics – Affiche les informations de «métriques» pour l'application actuelle; il est également sensible par défaut

  • /trace – Affiche les informations de trace (par défaut les dernières requêtes HTTP)

Nous pouvons trouver la liste complète des points de terminaison existants suron the official docs.

3.2. Configuration des points de terminaison existants

Chaque point de terminaison peut être personnalisé avec des propriétés utilisant le format suivant:endpoints.[endpoint name].[property to customize]

Trois propriétés sont disponibles:

  • id – par lequel ce point de terminaison sera accessible via HTTP

  • enabled - si vrai, il est possible d'y accéder sinon pas

  • sensitive - si true, alors besoin de l'autorisation pour afficher des informations cruciales sur HTTP

Par exemple, ajoutez les propriétés suivantes pour personnaliser le point de terminaison /beans:

endpoints.beans.id=springbeans
endpoints.beans.sensitive=false
endpoints.beans.enabled=true

3.3. Point final/health

The /health endpoint is used to check the health or state of the running application. Il est généralement exercé par un logiciel de surveillance pour nous alerter si l'instance en cours d'exécution tombe en panne ou devient défectueuse pour d'autres raisons. E.g. Problèmes de connectivité avec notre base de données, manque d'espace disque…

Par défaut, seules les informations sur la santé sont présentées aux accès non autorisés via HTTP:

{
    "status" : "UP"
}

Ces informations de santé sont collectées à partir de tous les beans implémentant l'interfaceHealthIndicator configurée dans notre contexte d'application.

Certaines informations renvoyées parHealthIndicator sont de nature sensible - mais nous pouvons configurerendpoints.health.sensitive=false pour exposer des informations plus détaillées telles que l'espace disque, la connectivité du courtier de messagerie, les contrôles personnalisés, etc.

Nous pourrions égalementimplement our own custom health indicator - qui peut collecter tout type de données de santé personnalisées spécifiques à l'application et l'exposer automatiquement via le point de terminaison/health:

@Component
public class HealthCheck implements HealthIndicator {

    @Override
    public Health health() {
        int errorCode = check(); // perform some specific health check
        if (errorCode != 0) {
            return Health.down()
              .withDetail("Error Code", errorCode).build();
        }
        return Health.up().build();
    }

    public int check() {
        // Our logic to check health
        return 0;
    }
}

Voici à quoi ressemblerait le résultat:

{
    "status" : "DOWN",
    "myHealthCheck" : {
        "status" : "DOWN",
        "Error Code" : 1
     },
     "diskSpace" : {
         "status" : "UP",
         "free" : 209047318528,
         "threshold" : 10485760
     }
}

3.4. Point final/info

Nous pouvons également personnaliser les données affichées par le point de terminaison/info - par exemple:

info.app.name=Spring Sample Application
info.app.description=This is my first spring boot application
info.app.version=1.0.0

Et l'exemple de sortie:

{
    "app" : {
        "version" : "1.0.0",
        "description" : "This is my first spring boot application",
        "name" : "Spring Sample Application"
    }
}

3.5. Point final/metrics

The metrics endpoint publishes information about OS, JVM as well as application level metrics. Une fois activé, nous obtenons des informations telles que la mémoire, le tas, les processeurs, les threads, les classes chargées, les classes déchargées, les pools de threads ainsi que des métriques HTTP.

Voici à quoi ressemble la sortie de ce point de terminaison prête à l'emploi:

{
    "mem" : 193024,
    "mem.free" : 87693,
    "processors" : 4,
    "instance.uptime" : 305027,
    "uptime" : 307077,
    "systemload.average" : 0.11,
    "heap.committed" : 193024,
    "heap.init" : 124928,
    "heap.used" : 105330,
    "heap" : 1764352,
    "threads.peak" : 22,
    "threads.daemon" : 19,
    "threads" : 22,
    "classes" : 5819,
    "classes.loaded" : 5819,
    "classes.unloaded" : 0,
    "gc.ps_scavenge.count" : 7,
    "gc.ps_scavenge.time" : 54,
    "gc.ps_marksweep.count" : 1,
    "gc.ps_marksweep.time" : 44,
    "httpsessions.max" : -1,
    "httpsessions.active" : 0,
    "counter.status.200.root" : 1,
    "gauge.response.root" : 37.0
}

Afin de collecter des métriques personnalisées, nous prenons en charge les «jauges», c'est-à-dire les instantanés de données à valeur unique, et les «compteurs», c'est-à-dire incrementing/decrementing metrics.

Implémentons nos propres métriques personnalisées dans le point de terminaison/metrics. Par exemple, nous allons personnaliser le flux de connexion pour enregistrer une tentative de connexion réussie et échouée:

@Service
public class LoginServiceImpl {

    private final CounterService counterService;

    public LoginServiceImpl(CounterService counterService) {
        this.counterService = counterService;
    }

    public boolean login(String userName, char[] password) {
        boolean success;
        if (userName.equals("admin") && "secret".toCharArray().equals(password)) {
            counterService.increment("counter.login.success");
            success = true;
        }
        else {
            counterService.increment("counter.login.failure");
            success = false;
        }
        return success;
    }
}

Voici à quoi pourrait ressembler la sortie:

{
    ...
    "counter.login.success" : 105,
    "counter.login.failure" : 12,
    ...
}

Notez que les tentatives de connexion et autres événements liés à la sécurité sont disponibles dans l’actionneur en tant qu’événements d’audit.

3.6. Créer un nouveau point de terminaison

En plus d'utiliser les points de terminaison existants fournis par Spring Boot, nous pourrions également en créer un entièrement nouveau.

Premièrement, nous devons faire en sorte que le nouveau point de terminaison implémente l’interfaceEndpoint<T>:

@Component
public class CustomEndpoint implements Endpoint> {

    @Override
    public String getId() {
        return "customEndpoint";
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public boolean isSensitive() {
        return true;
    }

    @Override
    public List invoke() {
        // Custom logic to build the output
        List messages = new ArrayList();
        messages.add("This is message 1");
        messages.add("This is message 2");
        return messages;
    }
}

Afin d'accéder à ce nouveau point final, sonid est utilisé pour le mapper, c'est-à-dire nous pourrions l'exercer en frappant/customEndpoint.

Sortie:

[ "This is message 1", "This is message 2" ]

3.7. Personnalisation supplémentaire

Pour des raisons de sécurité, nous pouvons choisir d'exposer les points de terminaison de l'actionneur sur un port non standard - la propriétémanagement.port peut facilement être utilisée pour configurer cela.

En outre, comme nous l'avons déjà mentionné, dans 1.x. Actionneur configure son propre modèle de sécurité, basé sur Spring Security mais indépendant du reste de l'application. Par conséquent, nous pouvons modifier la propriétémanagement.address pour restreindre l'endroit où les points de terminaison sont accessibles sur le réseau:

#port used to expose actuator
management.port=8081

#CIDR allowed to hit actuator
management.address=127.0.0.1

#Whether security should be enabled or disabled altogether
management.security.enabled=false

En outre, tous les points de terminaison intégrés à l'exception de/info sont sensibles par défaut. Si l'application utilise Spring Security, nous pouvons sécuriser ces points de terminaison en définissant les propriétés de sécurité par défaut (nom d'utilisateur, mot de passe et rôle) dans le fichier application.properties:

security.user.name=admin
security.user.password=secret
management.security.role=SUPERUSER

4. Actionneur Spring Boot 2.x

Dans 2.x, Actuator conserve son intention fondamentale, mais simplifie son modèle, étend ses capacités et intègre de meilleurs paramètres par défaut.

Premièrement, cette version devient agnostique sur le plan technologique. En outre, il simplifie son modèle de sécurité en le fusionnant avec celui de l'application.

Enfin, parmi les différents changements, il est important de garder à l’esprit que certains d’entre eux se cassent. Cela inclut les requêtes / réponses HTTP ainsi que les API Java.

De plus, la dernière version prend désormais en charge le modèle CRUD, par opposition à l'ancien modèle RW (lecture / écriture).

4.1. Support technologique

Avec sa deuxième version majeure, Actuator est maintenant indépendant de la technologie alors que dans 1.x, il était lié à MVC, donc à l'API Servlet.

Dans 2.x, Actuator définit son modèle, connectable et extensible, sans s'appuyer sur MVC pour cela.

Par conséquent, avec ce nouveau modèle, nous pouvons tirer parti de MVC ainsi que de WebFlux en tant que technologie Web sous-jacente.

De plus, les technologies à venir pourraient être ajoutées en mettant en œuvre les bons adaptateurs.

Enfin, JMX reste pris en charge pour exposer les systèmes d'extrémité sans code supplémentaire.

4.2. Changements importants

Contrairement aux versions précédentes,Actuator comes with most endpoints disabled.

Ainsi, les deux seuls disponibles par défaut sont/health et/info.

Si nous voulions tous les activer, nous pourrions définirmanagement.endpoints.web.exposure.include=*.. Sinon, nous pourrions lister les points de terminaison qui devraient être activés.

L'actionneur partage désormais la configuration de sécurité avec les règles de sécurité habituelles de l'application. Par conséquent, le modèle de sécurité est considérablement simplifié.

Par conséquent, pour modifier les règles de sécurité de l'actionneur, nous pourrions simplement ajouter une entrée pour/actuator/**:

@Bean
public SecurityWebFilterChain securityWebFilterChain(
  ServerHttpSecurity http) {
    return http.authorizeExchange()
      .pathMatchers("/actuator/**").permitAll()
      .anyExchange().authenticated()
      .and().build();
}

Nous pouvons trouver plus de détails sur lesbrand new Actuator official docs.

Aussi,by default, all Actuator endpoints are now placed under the /actuator path.

Comme dans la version précédente, nous pouvons modifier ce chemin, en utilisant la nouvelle propriétémanagement.endpoints.web.base-path.

4.3. Points de terminaison prédéfinis

Jetons un coup d'œil à certains points de terminaison disponibles, la plupart d'entre eux étant déjà disponibles dans la version 1.x.

Néanmoins,some endpoints have been added, some removed and some have been restructured:

  • /auditevents – répertorie les événements liés à l'audit de sécurité tels que la connexion / déconnexion de l'utilisateur. En outre, nous pouvons filtrer par principal ou type parmi d'autres champs

  • /beans – rdéfinit tous les beans disponibles dans nosBeanFactory. Contrairement à/auditevents, il ne prend pas en charge le filtrage

  • /conditions – anciennement connu sous le nom de /autoconfig, génère un rapport des conditions autour de la configuration automatique

  • /configprops – nous permet de récupérer tous les beans@ConfigurationProperties

  • /env – renvoie les propriétés de l'environnement actuel. De plus, nous pouvons récupérer des propriétés uniques

  • /flyway – fournit des détails sur les migrations de notre base de données Flyway

  • /health – résume l'état de santé de notre application

  • /heapdump – construit et retourne un vidage de tas de la JVM utilisée par notre application

  • /info – renvoie des informations générales. Il peut s'agir de données personnalisées, d'informations de construction ou de détails sur la dernière validation.

  • /liquibase – be comporte comme/flyway mais pour Liquibase

  • /logfile – renvoie les journaux d'application ordinaires

  • /loggers – nous permet d'interroger et de modifier le niveau de journalisation de notre application

  • /metrics – détaille les métriques de notre application. Cela peut inclure des mesures génériques ainsi que des mesures personnalisées

  • /prometheus – renvoie des métriques comme la précédente, mais formatées pour fonctionner avec un serveur Prometheus

  • /scheduledtasks – fournit des détails sur chaque tâche planifiée dans notre application

  • /sessions – répertorie les sessions HTTP étant donné que nous utilisons Spring Session

  • /shutdown – effectue un arrêt progressif de l'application

  • /threaddump – vide les informations de thread de la JVM sous-jacente

4.4. Indicateurs de santé

Comme dans la version précédente, nous pouvons facilement ajouter des indicateurs personnalisés. Contrairement aux autres API, les abstractions permettant de créer des points de terminaison d'intégrité personnalisés restent inchangées. Cependant,a new interface ReactiveHealthIndicator has been added to implement reactive health checks.

Jetons un coup d'œil à un simple bilan de santé réactif personnalisé:

@Component
public class DownstreamServiceHealthIndicator implements ReactiveHealthIndicator {

    @Override
    public Mono health() {
        return checkDownstreamServiceHealth().onErrorResume(
          ex -> Mono.just(new Health.Builder().down(ex).build())
        );
    }

    private Mono checkDownstreamServiceHealth() {
        // we could use WebClient to check health reactively
        return Mono.just(new Health.Builder().up().build());
    }
}

A handy feature of health indicators is that we can aggregate them as part of a hierarchy. Par conséquent, en suivant l'exemple précédent, nous pourrions regrouper tous les services en aval sous une catégoriedownstream-services. Cette catégorie serait saine tant que tous lesservice imbriqués étaient accessibles.

Les vérifications de l'état composites sont présentes dans 1.x àCompositeHealthIndicator. De plus, dans 2.x, nous pourrions utiliserCompositeReactiveHealthIndicator pour son homologue réactif.

Contrairement à Spring Boot 1.x, l'indicateurendpoints. .sensitive a été supprimé. Pour masquer le rapport de santé complet, nous pouvons profiter des nouveauxmanagement.endpoint.health.show-details.. Cet indicateur est faux par défaut.

4.5. Métriques dans Spring Boot 2

In Spring Boot 2.0, the in-house metrics were replaced with Micrometer support. Ainsi, nous pouvons nous attendre à des changements de rupture. Si notre application utilisait des services métriques tels queGaugeService or CounterService, ils ne seront plus disponibles.

Au lieu de cela, nous sommes censés interagir directement avecMicrometer. Dans Spring Boot 2.0, nous obtiendrons un bean de typeMeterRegistry automatiquement configuré pour nous.

De plus, Micrometer fait désormais partie des dépendances d'Actuator. Par conséquent, nous devrions pouvoir y aller aussi longtemps que la dépendance de l'actionneur est dans le chemin de classe.

De plus, nous obtiendrons une toute nouvelle réponse du point de terminaison/metrics:

{
  "names": [
    "jvm.gc.pause",
    "jvm.buffer.memory.used",
    "jvm.memory.used",
    "jvm.buffer.count",
    // ...
  ]
}

Comme nous pouvons le constater dans l'exemple précédent, il n'y a pas de métrique réelle comme celle obtenue dans 1.x.

Pour obtenir la valeur réelle d'une métrique spécifique, nous pouvons maintenant accéder à la métrique souhaitée, c'est-à-dire/actuator/metrics/jvm.gc.pause et obtenir une réponse détaillée:

{
  "name": "jvm.gc.pause",
  "measurements": [
    {
      "statistic": "Count",
      "value": 3.0
    },
    {
      "statistic": "TotalTime",
      "value": 7.9E7
    },
    {
      "statistic": "Max",
      "value": 7.9E7
    }
  ],
  "availableTags": [
    {
      "tag": "cause",
      "values": [
        "Metadata GC Threshold",
        "Allocation Failure"
      ]
    },
    {
      "tag": "action",
      "values": [
        "end of minor GC",
        "end of major GC"
      ]
    }
  ]
}

Comme nous pouvons le constater, les métriques sont maintenant beaucoup plus complètes. Y compris non seulement des valeurs différentes mais aussi des méta-données associées.

4.6. Personnalisation du point de terminaison/info

Le point de terminaison/info reste inchangé. As before, we can add git details using the Maven or Gradle respective dependency:


    pl.project13.maven
    git-commit-id-plugin

De même,we could also include build information including name, group, and version using the Maven or Gradle plugin:


    org.springframework.boot
    spring-boot-maven-plugin
    
        
            
                build-info
            
        
    

4.7. Création d'un point de terminaison personnalisé

Comme nous l'avons souligné précédemment, nous pouvons créer des points de terminaison personnalisés. Cependant, Spring Boot 2 a repensé le moyen d'y parvenir pour prendre en charge le nouveau paradigme indépendant de la technologie.

Let’s create an Actuator endpoint to query, enable and disable feature flags in our application:

@Component
@Endpoint(id = "features")
public class FeaturesEndpoint {

    private Map features = new ConcurrentHashMap<>();

    @ReadOperation
    public Map features() {
        return features;
    }

    @ReadOperation
    public Feature feature(@Selector String name) {
        return features.get(name);
    }

    @WriteOperation
    public void configureFeature(@Selector String name, Feature feature) {
        features.put(name, feature);
    }

    @DeleteOperation
    public void deleteFeature(@Selector String name) {
        features.remove(name);
    }

    public static class Feature {
        private Boolean enabled;

        // [...] getters and setters
    }

}

Pour obtenir le point final, nous avons besoin d'un haricot. Dans notre exemple, nous utilisons@Component pour cela. De plus, nous devons décorer ce bean avec@Endpoint.

Le chemin de notre point de terminaison est déterminé par le paramètreid de@Endpoint, dans notre cas, il acheminera les requêtes vers/actuator/features.

Une fois prêt, nous pouvons commencer à définir les opérations en utilisant:

  • @ReadOperation – il sera mappé vers HTTPGET

  • @WriteOperation - il sera mappé vers HTTPPOST

  • @DeleteOperation - il sera mappé vers HTTPDELETE

Lorsque nous exécutons l'application avec le noeud final précédent dans notre application, Spring Boot l'enregistre.

Un moyen rapide de vérifier ceci consisterait à vérifier les journaux:

[...].WebFluxEndpointHandlerMapping: Mapped "{[/actuator/features/{name}],
  methods=[GET],
  produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features],
  methods=[GET],
  produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features/{name}],
  methods=[POST],
  consumes=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features/{name}],
  methods=[DELETE]}"[...]

Dans les journaux précédents, nous pouvons voir comment WebFlux expose notre nouveau point de terminaison. Pourrions-nous passer à MVC, il déléguera simplement sur cette technologie sans avoir à changer de code.

De plus, nous avons quelques considérations importantes à garder à l'esprit avec cette nouvelle approche:

  • Il n'y a pas de dépendances avec MVC

  • Toutes les métadonnées présentes en tant que méthodes avant (sensitive, enabled…) n'existe plus. Nous pouvons cependant activer ou désactiver le point de terminaison en utilisant@Endpoint(id = “features”, enableByDefault = false)

  • Contrairement à la version 1.x, il n’est plus nécessaire d’étendre une interface donnée

  • Contrairement à l'ancien modèle de lecture / écriture, nous pouvons maintenant définir les opérationsDELETE en utilisant@DeleteOperation

4.8. Extension des points de terminaison existants

Imaginons que nous voulions nous assurer que l’instance de production de notre application n’est jamais une version deSNAPSHOT. Nous avons décidé de le faire en modifiant le code d'état HTTP du point de terminaison de l'actionneur qui renvoie ces informations, c'est-à-dire/info. Si notre application était unSNAPSHOT. Nous obtiendrions un code de statutHTTPdifférent.

We can easily extend the behavior of a predefined endpoint using the @EndpointExtension annotations, ou ses spécialisations plus concrètes@EndpointWebExtension ou@EndpointJmxExtension:

@Component
@EndpointWebExtension(endpoint = InfoEndpoint.class)
public class InfoWebEndpointExtension {

    private InfoEndpoint delegate;

    // standard constructor

    @ReadOperation
    public WebEndpointResponse info() {
        Map info = this.delegate.info();
        Integer status = getStatus(info);
        return new WebEndpointResponse<>(info, status);
    }

    private Integer getStatus(Map info) {
        // return 5xx if this is a snapshot
        return 200;
    }
}

4.9. Activer tous les points de terminaison

In order to access the actuator endpoints using HTTP, we need to both enable and expose them. Par défaut, tous les points de terminaison sauf/shutdown sont activés. Seuls les points de terminaison/health et/info sont exposés par défaut.

Nous devons ajouter la configuration suivante pour exposer tous les points de terminaison:

management.endpoints.web.exposure.include=*

Pour activer explicitement un point de terminaison spécifique (par exemple, utilisez/shutdown), we:

management.endpoint.shutdown.enabled=true

Pour exposer tous les points de terminaison activés sauf un (par exemple/loggers), nous utilisons:

management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=loggers

5. Sommaire

Dans cet article, nous avons parlé de Spring Boot Actuator. Nous avons commencé à définir ce que signifie Actionneur et ce qu’il fait pour nous.

Ensuite, nous nous sommes concentrés sur Actuator pour la version actuelle de Spring Boot, 1.x. discutez de la façon de l’utiliser, modifiez-le et étendez-le.

Ensuite, nous avons discuté de l’actionneur dans Spring Boot 2. Nous nous sommes concentrés sur les nouveautés et avons profité de WebFlux pour exposer notre point de terminaison.

Nous avons également parlé des changements de sécurité importants que nous pouvons trouver dans cette nouvelle itération. Nous avons discuté de certains paramètres populaires et de la façon dont ils ont également changé.

Enfin, nous avons montré comment personnaliser et étendre Actuator.

Comme toujours, nous pouvons trouver le code utilisé dans cet article sur GitHub pour lesSpring Boot 1.x etSpring Boot 2.x.