IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Création d'une annotation pour exécuter du code avant/après une méthode


Sujet :

Java

  1. #1
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut Création d'une annotation pour exécuter du code avant/après une méthode
    Bonjour à tous,

    En Java 7, je me pose la question de comment écrire une annotation custom pour exécuter du code avant et après une méthode (l'idée est de chronométrer le temps d'exécution de certaines de mes méthodes).
    La méthode classique mais que je trouve redondante est de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public void maMethode() {
        long debut = new Date().getTime();
        // ici le contenu de la méthode
        System.out.println("Durée : " + new Date().getTime() - debut);
    }
    (l'exemple ici reste volontairement simple, l'usage de new Date(), getTime() ou même System.out.println n'est pas du tout la question)

    En réalité, mon cas est un tout petit peu plus compliqué puisqu'il stocke les durées d'exécution des méthodes qui sont appelées plusieurs fois pour n'afficher que leur temps moyen d'exécution à la toute fin de mon programme.
    Dans les faits, ça donne quelque chose dans ce genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public void maMethode() {
        startBench("un identifiant quelconque");
        // ici le contenu de la méthode
        stopBench("un identifiant quelconque");
    }
    Dans l'idée, je pensais créer une annotation du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Bench {
        String value();
    }
    et l'utiliser comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @Bench("un identifiant quelconque")
    public void maMethode() {
        // ici le contenu de la méthode
    }
    Mais voilà : comment faire en sorte d'exécuter startBench("un identifiant quelconque"); avant d'exécuter ma méthode et stopBench("un identifiant quelconque"); à la fin de ma méthode ?

    Après moults recherches sur le net, impossible de trouver une solution pour ce problème qui me semble pourtant élémentaire...
    Je précise que la solution que je recherche concerne une vraie application, pas une "application" web.
    J'aimerais idéalement définir une méthode onStart et une méthode onFinish dans mon annotation mais comment faire en sorte qu'elles soient appelées automatiquement ?

    Merci d'avance pour votre aide et vos pistes
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

  2. #2
    Membre averti
    Homme Profil pro
    Architecte technique
    Inscrit en
    Mai 2020
    Messages
    325
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : Mai 2020
    Messages : 325
    Points : 436
    Points
    436
    Par défaut
    Bonjour,

    Je pense qu'il y à deux solutions:

    La première serait d'utiliser un framework d'AOP (Aspect Oriented Programming) dans votre application. Certains fonctionnent avec des déclarations de point de coupe, d'autres avec des annotations à vous de voir ce qui vous convient le mieux.

    L'autre solution est de créer un processeur d'annotations que vous renseignez à votre compilateur. Mais il faudra faire de la manipulation de code pour injecter vos appels startBench et stopBench au début et à la fin de votre méthode plus gèrer les try { .. } catch { .. } finally { .. }.


    Une troisième approche, qui n'est pas vraiment une réponse à votre question, serait d'utiliser une librairie existante pour faire ce travail. C'est à mon sens (sans connaître vos besoins) la solution la plus efficace.

  3. #3
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut
    Bonjour

    Pour éclaircir un peu le domaine auquel cela doit s'appliquer, il s'agit d'une application client lourd qui grosso modo pourrait s'apparenter à un moteur 3D basé sur OpenGL. Pour reprendre les solutions proposées :

    1. Les librairies existantes sont malheureusement souvent basées sur des annotations Spring ou autre, et répondent du coup plutôt à des besoins lié au web (configuration des annotations via des beans définis dans des configurations Tomcat, par exemple). La plupart des solutions sur lesquelles je tombe sont basées là-dessus, malheureusement pour moi… J'ai donc écarté cette option pour le moment.

    2. Le processeur d'annotation est une piste que j'ai commencé à explorer, mais je me suis rendu compte qu'au final, je devais explicitement lancer ce processeur d'annotations pour qu'il s'exécute. Mon application étant lancée comme un programme, lancer un processeur d'annotation en pré-requis me paraît un peu lourd et coûteux en terme de vitesse d'exécution (mes contraintes sont de garder une application qui s'ouvre rapidement et qui maintienne une vitesse d'exécution élevée pour garantir les 60 FPS).

    3. En troisième solution, l'approche AOP m'intéressait beaucoup car semblant la plus adaptée à mes besoins. Mais mes connaissances sont un peu trop limitées dans ce domaine, et je n'arrive pas à savoir comment m'y prendre techniquement.
    Je n'arrive pas à savoir si :
    • une annotation sur une méthode permet de déclencher un traitement au moment où la méthode en question se lance,
    • un listener doit être mis en place quelque part, en scannant toutes les méthodes annotées au préalable


    Si c'est la première option, l'idée serait d'encapsuler l'appel à la méthode, en l'encadrant par mes startBench / stopBench.
    Si par contre c'est la seconde option, pas sûr encore une fois que ça respecte mes contraintes concernant la vitesse d'exécution…

    Je ne sais pas si tout cela est très clair, n'hésitez pas en cas d'interrogation ^^
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

  4. #4
    Membre chevronné
    Avatar de professeur shadoko
    Homme Profil pro
    retraité nostalgique Java SE
    Inscrit en
    Juillet 2006
    Messages
    1 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 75
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : retraité nostalgique Java SE

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 257
    Points : 1 855
    Points
    1 855
    Par défaut
    il existe une solution particulièrement facile et crade (quick and dirty) : mettre aux points critiques un assert qui lance une méthode qui rend toujours true
    après tu exécutes avec ou sans assertion activée!
    assert n'est pas du tout fait pour ça mais hein c'est "facile et crade"
    J'ai des principes: je peux toujours trouver une bonne raison pour les contredire .... mais j'ai des principes!
    (mon excellent bouquin sur Java : https://eska-publishing.com/fr/livre...822407076.html)

  5. #5
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut
    Effectivement, un usage détourné assez particulier, j'y aurais pas pensé...

    Mais vu ce qu'il implique, au final, appeler manuellement mes méthodes startBench et stopBench respectivement en début et en fin des methodes à mesurer est à peine plus coûteux, et surtout un peu plus propre.
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

  6. #6
    Membre chevronné
    Avatar de professeur shadoko
    Homme Profil pro
    retraité nostalgique Java SE
    Inscrit en
    Juillet 2006
    Messages
    1 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 75
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : retraité nostalgique Java SE

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 257
    Points : 1 855
    Points
    1 855
    Par défaut
    l'avantage du "assert" détourné c'est que tu peux activer tes méthodes à la demande (l'exécution n'en est pas systématique) et ça c'est important!
    J'ai des principes: je peux toujours trouver une bonne raison pour les contredire .... mais j'ai des principes!
    (mon excellent bouquin sur Java : https://eska-publishing.com/fr/livre...822407076.html)

  7. #7
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par Chen norris Voir le message
    Après moults recherches sur le net, impossible de trouver une solution pour ce problème qui me semble pourtant élémentaire...
    Oui enfin, c'est quand même assez clairement une problématique de programmation orientée aspect. Si Java était orienté aspect, ça se saurait.

    Citation Envoyé par Chen norris Voir le message
    1. Les librairies existantes sont malheureusement souvent basées sur des annotations Spring ou autre, et répondent du coup plutôt à des besoins lié au web (configuration des annotations via des beans définis dans des configurations Tomcat, par exemple).
    Absolument pas. Spring fonctionne avec tout, et si les gens s'en servent surtout pour le web, ce n'est pas son problème. Rien de Spring n'est lié à Tomcat. Il aide juste des fois que ça t'intéresserait d'utiliser Tomcat, mais si ce n'est pas le cas, ne le fais pas.

    Tu peux toujours refaire la même chose : Organiser ton code en beans interconnectés les uns aux autres par annotation ou implication, avec un moteur qui se charge de les interconnecter au lieu de le faire toi-même. Pour plus de simplicité, programme-les tous par interface. Puis fais en sorte que ce moteur, quand il tombe sur une annotation @Bench sur une méthode, crée un proxy de l'interface qui mesure le temps passé à exécuter la méthode, et à l'intérieur appelle la classe concrète qui aurait normalement été liée directement.

    Bien sûr c'est exactement ce que fait Spring AOP, et il y a 0% de web là-dedans, donc ça a pas l'air bien malin de le refaire. Mais c'est tout à fait possible.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut
    Si Java était orienté aspect, ça se saurait.
    Je comprends un peu mieux pourquoi je n'arrive pas à trouver de solution facilement, ça me rassure

    Pour plus de simplicité, programme-les tous par interface. Puis fais en sorte que ce moteur, quand il tombe sur une annotation @Bench sur une méthode, crée un proxy de l'interface
    Je pense que c'est effectivement ce qui se rapproche le plus de ce que je cherche à faire. Si je comprends bien, ça donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class ClasseA {
        public void methodeA1() {
            ...
        }
        public void methodeA2() {
            ...
        }
    }
     
    public class ClasseB {
        public void methodeB1() {
            ...
        }
        public void methodeB2() {
            ...
        }
    }
    qui sont lancées via un moteur global dans lequel mes classes sont injectées en tant que beans comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Engine {
        @Bean
        ClasseA classeA;
     
        @Bean
        ClasseB classeB;
     
        ...
    }
    Et au moment de lancer les méthodes de mes beans, je vérifie si elles sont annotées @Bench ou pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if (classeA.traitementA.hasAnnotation(Bench.class))
        classeA.startBench("classeA.traitementA");
    classeA.traitementA();
    if (classeA.traitementA.hasAnnotation(Bench.class))
        classeA.stopBench("classeA.traitementA");
    J'ai bon ?

    Et question corollaire : la vérification de la présence d'annotation sur une méthode nécessite systématiquement de la réflexivité ?
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

  9. #9
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    C'est une manière de faire moins générale, donc plus dirigée vers ton besoin, oui.

    Citation Envoyé par Chen norris Voir le message
    Et question corollaire : la vérification de la présence d'annotation sur une méthode nécessite systématiquement de la réflexivité ?
    Ouaip.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  10. #10
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut
    OK, c'est un peu ce que je craignais. La réflexion n'étant pas synonyme de performance, je pense que je vais m'arrêter là dans mes recherches et m'en tenir à mes appels explicites startBench / stopBench.
    Je note le sujet comme résolu, merci pour toutes vos pistes
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

  11. #11
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Euh oui non mais, il y a moyen de chercher au démarrage du programme où sont les annotations, et de faire en sorte que tous les passages par là soient mesurés, sans avoir à refaire de la réflectivité.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  12. #12
    Membre averti
    Homme Profil pro
    Architecte technique
    Inscrit en
    Mai 2020
    Messages
    325
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : Mai 2020
    Messages : 325
    Points : 436
    Points
    436
    Par défaut
    thelvin à raison. C'est une étape à faire une fois au lancement du programme. Ensuite vous pouvez travailler avec les Proxy ou le faire à la main avec de la composition.

    https://docs.oracle.com/javase/8/doc...ect/Proxy.html

  13. #13
    Membre actif Avatar de Chen norris
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    216
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 216
    Points : 248
    Points
    248
    Par défaut
    Le vocabulaire officiel et moi faisant parfois un peu deux, je suis allé cherché un tuto sur la mise en place de proxy… et je me rends compte que c'est quelque chose que j'ai en réalité déjà mis en place pour gérer mes associations touches du clavier / actions. Grosso modo, j'ai un fichier de properties qui est parsé au lancement de mon appli pour générer une Map<Touche de clavier, Méthode à lancer> et il se trouve que les valeurs de cette map, ce sont justement des objets qui invoquent des méthodes. Pour mon bench, il suffit que je fasse la même chose au démarrage de mon appli. La seule différence, c'est qu'au lieu de parcourir un fichier de properties, je dois juste détecter les méthodes annotées avec un intercepteur (c'est sans doute sur cette dernière partie que je manque de connaissance).
    Au final, j'avais écarté cette hypothèse car je pensais que c'était coûteux à chaque itération mais si je comprends bien, c'est plutôt l'initialisation qui est coûteuse, pas l'exécution
    Chen norris
    C/C++, C#, Java, PHP & SQL coder
    Web developer

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 08/04/2020, 14h30
  2. Réponses: 4
    Dernier message: 16/09/2010, 17h30
  3. quelques problèmes pour exécuter mes codes
    Par djimangue dans le forum Langage
    Réponses: 6
    Dernier message: 18/12/2007, 01h00
  4. Pas assez de mémoire pour exécuter un code
    Par med_ellouze dans le forum Langage
    Réponses: 6
    Dernier message: 11/08/2007, 02h51
  5. Allocation mémoire pour exécution de code généré
    Par mchk0123 dans le forum x86 32-bits / 64-bits
    Réponses: 6
    Dernier message: 06/04/2007, 16h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo