Tutoriel pour apprendre à exécuter une application Java au travers d'un service Windows

Application Java en tant que service Windows

Tristan Fleury

Ce tutoriel vous explique comment faire fonctionner une application développée en Java en tant que service Windows. Pour permettre ce fonctionnement, une API JavaService est nécessaire. L'intérêt de cette API est de permettre une interaction complète avec l'instance JAVA, de pouvoir passer des arguments au lancement et d'appeler une méthode spécifique lors de l'arrêt du service.

Ce système n'est valable que sur des OS Windows. Une connaissance minimum du langage Java est nécessaire.

Commentez ♪

- Titre : Tutoriel pour apprendre à exécuter une application Java au travers d'un service Windows

- Auteur : Tristan Fleury

- Parution : 3 janvier 2016

- Public visé :

- Licence : Le contenu de cet article est rédigé par Viduc et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.

Voir également :

- NetBeans

- Windows

- Java

Sommaire

- I. Introduction

- II. Prérequis

- III. Création du service

- III-A. Application Java

- III-B. Création du service

- III-B-1. Structure / Dossier

- III-B-2. JavaService

- IV. Paramètres

- IV-A. Sortie standard

- IV-B. Arguments

- V. Arrêt propre du service

- VI. Suppression du service

- VII. Autres commandes et options

- VIII. Conclusion

- IX. Remerciement

I - Introduction

Dans les systèmes d'exploitation de type Windows NT, un service (ou service Windows) est un programme qui fonctionne en arrière-plan. Il est similaire à un daemon d'Unix. Un service doit se conformer aux règles d'interface et aux protocoles du Service Control Manager, le composant chargé de la gestion des services.

Les services peuvent être configurés pour démarrer lorsque le système d'exploitation est démarré et fonctionner en arrière-plan tant que Windows est en cours d'exécution. En variante, ils peuvent être lancés manuellement par l'utilisateur ou par un événement qui a besoin du service. Les systèmes d'exploitation de type Windows NT incluent de nombreux services. Ceux-ci sont rattachés à trois comptes d'utilisateur : le compte Système, le compte Service réseau et le compte Service local. Parce que les services sont associés à leurs propres comptes utilisateur dédiés, ils peuvent fonctionner sans qu'un utilisateur soit connecté au système d'exploitation. Les services sont souvent associés à des processus hôtes pour les services Windows.

Source : Wikipédia.

Une application réalisée en Java ne peut être lancée directement en tant que service Windows. Nous allons découvrir comment créer un service Windows spécifique pour lancer cette application. Pour ce faire nous ferons appel à une API nommée JavaService.

II - Prérequis

L'OS sur lequel doit s'exécuter le programme doit être de type Microsoft Windows en 32 ou 64 bits. Une JRE doit être installée.

III - Création du service

III-A - Application Java

La première étape consiste à créer une petite application Java qui va nous servir de test. Pour réaliser cette application, j'utilise l'IDE NetBeans, mais vous pouvez utiliser n'importe quel autre IDE.

L'application créée consiste en une boucle simple qui affichera un message toutes les cinq secondes. Nous rajouterons plus tard quelques modifications afin d'utiliser au maximum toutes les possibilités offertes par l'API.

class Test

1. /**

2. * Class Test pour le tutoriel JavaService

3. * @author Tristan Fleury

4. */

6. public class Test {

8. /**

9. * @param args the command line arguments

10. */

11. public static void main(String[] args) throws Exception {

12. while(true){

13. System.out.println("Ceci est un test");

14. Thread.sleep(5000);

15. }

16. }

18. }

Si vous testez ce code dans votre IDE vous obtiendrez ceci :

Compilez votre code pour obtenir votre jar.

III-B - Création du service

III-B-1 - Structure / Dossier

Pour simplifier la mise en place de l'ensemble, créer un dossier « Test » à la racine de votre système :

III-B-2 - JavaService

Télécharger l'API ici en fonction de votre Système d'Exploitation (32 ou 64 bit). Décompressez le fichier dans le dossier Test précédemment créé. Ne garder que le fichier nommé « JavaService.exe » :

Copier votre jar dans le même dossier :

Récupérer le chemin d'accès du fichier jvm.dll, il doit se trouver à cet emplacement :

« C:\Program Files\Java\jdk1.8.0_65\jre\bin\server\jvm.dll »

Ouvrez ensuite une console de commande en tant qu'administrateur :

Console en tant qu'administrateur

Déplacez-vous dans le dossier Test :

Déplacement dans dossier Test

Entrez ensuite cette commande :

commande dos

JavaService.exe -install "test" "c:\Program Files\Java\jdk1.8.0_65\jre\bin\server\jvm.dll" -Djava.class.path=c:\Test\test.jar -start Test -method main

Commande création du service

La commande se décompose comme suit :

JavaService.exe : c'est le programme appelé pour créer le service ;

-install : déclare au programme qu'il s'agit d'une installation ;

« test » : c'est le nom que l'on souhaite donner au service ;

« c:\Program Files\Java\jdk1.8.0_65\jre\bin\server\jvm.dll » : chemin d'accès à la jvm ;

-Djava.class.path=c:\Test\test.jar : emplacement de notre programme java (jar) ;

-start Test : class principale dans laquelle la méthode de lancement se trouve ;

-method main : la méthode appelée lors du lancement du programme.

Vous pouvez ensuite vérifier que le service a bien été créé en ouvrant le gestionnaire de services Windows (service.msc) :

Vérification du service créé

Vous pouvez démarrer le service en cliquant sur la petite flèche verte en haut du gestionnaire de service :

Démarrer service

Le service passe alors « En cours d'exécution » :

En cours

Bien sûr à ce stade vous ne voyez pas le résultat de cette exécution, le programme est lancé, mais la sortie standard n'est redirigée vers rien. Nous allons voir comment récupérer cette sortie.

La dernière vérification à faire est d'ouvrir le gestionnaire de tâches et de regarder si un processus nommé JavaService tourne bien. Il y a une petite flèche qui permet d'ouvrir le sous-processus, vous devriez avoir « test » :

Processus JavaService

IV - Paramètres

Maintenant que le service est créé, nous allons pouvoir ajouter des paramètres d'exécution (arguments et fichier de sortie) et voir comment obtenir la sortie standard dans un fichier.

IV-A - Sortie standard

Ouvrez la base de registre (regedit.exe), naviguez vers HKLM/SYSTEM/CurrentControlSet/Services :

bdr services

Dans la liste des services, vous devriez trouver un service nommé « test » :

bdr test

Les paramètres de base peuvent être modifiés comme la Description, le DisplayName etc. Ce qui nous intéresse se trouve dans le dossier Parameters, cliquez dessus et vous obtiendrez ceci :

bdr parameters

Vous retrouverez tous les paramètres que nous avons définis dans notre commande de création du service (jvm, class, etc.).

Nous allons ajouter un paramètre afin de définir un fichier pour la sortie standard. Faites un clic droit dans la fenêtre de droite puis cliquez sur « Nouveau » puis « Valeur Chaîne » et entrez « System.out File » :

System.out File

Double-cliquez sur la chaîne créée pour entrer la valeur suivante : c:\Test\test.txt :

test.txt

Relancez le service, attendez quelques dizaines de secondes, arrêtez le service et ouvrez le fichier test.txt qui s'est créé dans le dossier c:\Test, vous devriez obtenir ceci :

fichier sortie standard

Nous constatons que la sortie standard est bien redirigée vers ce fichier texte. L'intérêt est donc de pouvoir créer un fichier log pour votre application en utilisant simplement la sortie standard (System.out.println()).

IV-B - Arguments

Nous avons vu lors de la création du service que nous pouvions définir une class et une méthode de lancement. Si ce paramètre n'est pas renseigné lors de la création du service, l'API cherchera une class Main et une méthode main. Il est donc possible de choisir n'importe quel nom de méthode à lancer. Vous pouvez directement modifier ces valeurs dans la base de registre en changeant les champs Start Class et Start Method :

Méthode et Class Start

Il est également possible de passer des arguments à la méthode appelée. Nous allons modifier la valeur binaire nommée « Start Param Count » et lui donner la valeur 2 (le nombre d'arguments que nous allons passer) :

Modifier valeur param count

Puis nous allons ajouter deux nouvelles valeurs chaîne, la première nommée « Start Param Number 0 » avec comme valeur Viduc, et la seconde « Start Param Number 1 » avec comme valeur 5 :

ajout paramètre bdr

Nous allons modifier notre class java pour utiliser ces paramètres :

Ajout d'arguments

1. /**

2. * Class Test pour le tutoriel JavaService

3. * @author Tristan Fleury

4. */

6. public class Test {

8. /**

9. * @param args the command line arguments

10. */

11. public static void main(String[] args) throws Exception {

12. try{

13. System.out.println("Bonjour "+args[0]);

14. }

15. catch (ArrayIndexOutOfBoundsException e){

16. System.out.println("Bonjour, je ne vous connais pas");

17. }

18. try{

19. Integer i=0;

20. while(i<Integer.valueOf(args[1])){

21. System.out.println("Index de l'argument: "+i);

22. i++;

23. Thread.sleep(5000);

24. }

25. }

26. catch (ArrayIndexOutOfBoundsException e){

27. System.out.println("aucune valeur de boucle");

28. }

30. }

32. }

Si vous testez ce code dans votre IDE en ajoutant les arguments « Viduc » et « 5 » lors de l'exécution vous obtiendrez ceci :

Exécution avec arguments

Compilez votre code et remplacez le fichier jar du service par ce nouveau fichier. Supprimez le fichier test.txt puis relancez le service. Attendez une minute puis arrêter le service. Ouvrez le nouveau fichier test.txt, vous devriez obtenir ceci :

Sortie txt avec argument

On constate que les arguments sont bien pris en compte. Pour ajouter de nouveaux arguments, répéter l'opération en n'oubliant pas de changer la valeur du champ « Start Param Count » (doit correspondre au nombre d'arguments passés).

V - Arrêt propre du service

Il est possible d'ajouter une méthode qui sera appelée par le service lors de son arrêt. Si notre application tourne en boucle sur une écoute de port ou de queue par exemple, il peut être souhaitable d'arrêter tous nos processus proprement lors de l'arrêt du service. Si rien n'est prévu, l'arrêt se fera sous la forme d'un Ctrl+C.

Ouvrez la base de registre pour accéder aux paramètres de votre service. Ajoutez deux valeurs chaîne, la première nommée « Stop Class » avec comme valeur « Test » et la seconde « Stop Method » avec comme valeur « stop ».

Ajoutez ensuite une valeur DWORD 32 bits nommée « Stop Param Count » avec comme valeur « 0 » :

bdr stop

Modifiez votre code comme suit :

méthode stop

1. /**

2. * Class Test pour le tutoriel JavaService

3. * @author Tristan Fleury

4. */

6. public class Test {

8. static boolean start = true;

9. static Test test;

10. /**

11. * @param args the command line arguments

12. */

13. public static void main(String[] args) throws Exception {

14. try{

15. System.out.println("Bonjour "+args[0]);

16. }

17. catch (ArrayIndexOutOfBoundsException e){

18. System.out.println("Bonjour, je ne vous connais pas");

19. }

20. test = new Test();

21. test.maMethod();

22. }

24. public void maMethod() throws Exception{

25. while(start){

26. System.out.println("Exécution du test");

27. Thread.sleep(5000);

28. }

29. }

31. public static void stop(String[] args){

32. System.out.println("Arrêt du test");

33. test.start = false;

34. }

35. }

Compilez votre code et copiez votre fichier jar. N'oubliez pas de supprimer le fichier test.txt pour repartir proprement.

Relancez votre service test, attendez quelques secondes et ensuite arrêtez le service. Vous devriez obtenir ceci :

sortie méthode test

Il est bien sûr possible d'utiliser une autre class pour la méthode d'arrêt. Il est également possible de passer des arguments à la méthode stop de la même façon que pour la méthode de lancement (ajouter une valeur chaîne : « Stop Param Number X » et n'oubliez pas de mettre à jour la valeur de la chaîne « Stop Param Count »).

VI - Suppression du service

Pour supprimer le service créé, il vous suffit d'entrer cette commande :

uninstall

JavaService -uninstall Test

Cette commande est à lancer avec les droits « En tant qu'administrateur », Test est le nom de votre service.

VII - Autres commandes et options

D'autres commandes et options sont disponibles lors de la création du service :

Commandes : pour exécuter ces commandes, placez-vous dans le dossier qui contient le programme JavaService avec une console, entrez JavaService.exe suivi de la commande.

-help (ou -?) Liste les commandes disponibles.

-version Affiche la version actuelle du programme JavaService.

-license (ou -licence) Affiche la licence LGPL.

-install servicename Installe le service nommé avec les options de configuration spécifiques.

-queryconfig servicename (ou -query) Affiche les détails de configuration du service installé.

-status servicename Affiche le statut d'exécution du service.

-uninstall servicename Désinstalle le service.

Les options disponibles lors de la création du service sont les suivantes :

- service_name (obligatoire) - Le nom que vous souhaitez utiliser pour le service. C'est sous ce nom que votre service sera visible dans le gestionnaire de service ;

- jvm_library (obligatoire) - L'emplacement du fichier jvm.dll que vous voulez utiliser pour votre machine virtuelle Java. Pour Sun's Java 2 SDK, c'est généralement {JDK_HOME}\jre\bin\classic\jvm.dll ou {JDK_HOME}\jre\bin\hotspot\jvm.dll ;

- jvm_option* (optionnel) - Pour spécifier différents paramètres à passer à la JVM lors de l'instanciation. Ceux-ci peuvent inclure « -Djava.class.path= » pour spécifier un class path ou « -Xmx128m » pour spécifier la taille maximum de mémoire à 128 MB. Tous les paramètres que vous avez besoin d'utiliser lorsque vous lancez la commande java.exe devraient être spécifiés ici. Il n'y a pas de limite au nombre de paramètres pouvant être passés ;

- -start start_class (oligatoire) - Le nom de la classe que vous souhaitez utiliser quand vous lancez le service. Le nom doit être le nom complet ;

- -method start_method (optionnel) - Le nom de la méthode static qui doit être appelée lorsque vous lancez le service. La méthode doit être de type static, doit retourner un type void et doit accepter en argument un tableau de String (String[]). Si ce paramètre n'est pas présent ce sera une méthode main qui sera lancée ;

- -params start_parameter + (optionnel) - tous les paramètres à passer à la méthode appelée lors du lancement du service. Ils seront passés dans un tableau de String ;

- -stop stop_class (optionnel) - Le nom de la class qui doit être appelée lorsque vous arrêtez le service. Le nom doit être le nom complet. S’il n'y a pas de class stop spécifiée, le processus qui lance la machine virtuelle est simplement arrêté ;

- -method stop_method - (optionnel, mais seulement accepté si la class stop a été spécifiée) - Le nom de la méthode static de la class stop_class qui doit être appelée lors de l'arrêt du service. La méthode doit être de type static, doit retourner un type void et doit accepter un tableau d'argument de type String (String[]). Si ce paramètre n'est pas spécifié la méthode main sera prise par défaut ;

- -params stop_parameter+ (optionnel, mais seulement accepté si la class stop a été spécifiée) - Tous les paramètres à passer à la méthode appelée lors de l'arrêt du service. Ils seront passés dans un tableau de String ;

- -out out_log_file (optionnel) - Un fichier dans lequel la sortie System.out sera redirigée. Si ce paramètre n'est pas spécifié, la sortie ne sera pas redirigée ;

- -err err_log_file (optionnel) - Un fichier dans lequel la sortie System. err sera redirigée. Si ce paramètre n'est pas spécifié, la sortie ne sera pas redirigée ;

- -current current_dir (optionnel) - Un dossier à utiliser comme dossier courant. Si ce paramètre est spécifié, tous les path relatifs du service seront basés sur ce dossier ;

- -path extra_path (optionnel) - L'ajout d'un path pour le service. Ce path sera ajouté au path du système après que le service sera lancé. Il peut être utilisé pour spécifier des chemins de librairies additionnelles dont dépendraient des librairies natives ;

- -depends other_services (optionnel) - Un autre service ou plusieurs services séparés par des virgules qui doivent être lancés avant que votre service java soit démarré. Le ou les services seront démarrés automatiquement si besoin quand votre service sera lancé. De la même façon, votre service sera arrêté si un de ces services est arrêté ;

- -auto or -manual - (optionnel) paramètre qui indique si le service doit être lancé de façon automatique ou manuelle ;

- -shutdown seconds (optionnel) - Spécifie le temps pendant lequel le service peut s'arrêter. Si la valeur est dépassée, la jvm sera stoppée ,

- -user user_name (optionnel) - Spécifie l'utilisateur Windows qui sera employé pour lancer le service (le mot de passe sera requis). Les utilisateurs locaux seront spécifiés comme ceci : .\user_name alors que les utilisateurs domaines seront spécifiés comme suit : domaine\user_name ou user_name@domain ;

- -password password (optionnel) - Spécifie le mot de passe associé au compte utilisé avec le paramètre user ;

- -append or -overwrite - (optionnel) paramètre pour indiquer si la sortie standard et la sortie d'erreur doivent écraser ou ajouter les informations aux fichiers existants ;

- -description service_desc - (optionnel) - Paramètre qui permet de spécifier une description du service. Utiliser des guillemets pour les textes qui incluent des espaces. À noter que cette fonctionnalité n'est supportée que depuis Windows NT ou supérieur.

VIII - Conclusion

La création d'un service Windows pour faire tourner une application Java avec la possibilité d'interagir avec l'instance créée est un plus dans le monde Windows. Un exemple d'utilisation serait de créer un composant de gestion autonome d'un Active Directory en Java.

IX - Remerciement

Merci à toutes les personnes qui ont contribué à la rédaction de cet article, en particulier Mickael Baron pour sa relecture technique et jacques_jean pour sa relecture orthographique.

Commentez