[JAVA] Les temps peuvent venir? Programmation orientée aspect, qu'est-ce que le langage AspectJ?

introduction

Lors du séminaire, j'ai eu l'occasion de présenter des recherches dans mon domaine d'intérêt. Il n'y avait pas d'articles qui semblaient intéressants même après diverses recherches, et la seule chose qui semblait intéressante était l'orientation des aspects. C'est une technologie très ancienne, donc je pense que beaucoup de gens la connaissent déjà ou ne s'y intéressent pas, mais je l'ai trouvée intéressante, alors j'aimerais la présenter. J'espère que quiconque a lu cet article s'intéresse à l'orientation des aspects.

Qu'est-ce que l'orientation aspect?

Introduit comme orienté post-objet, la prochaine technologie après orienté objet Mais ce n'est pas le cas, l'orientation aspect est une technologie qui remplit les ** limites ** de l'orientation objet et la développe davantage.

En premier lieu en génie logiciel

Dans le logiciel, il est bon que le degré d'agrégation soit élevé et le degré de liaison soit faible. Cependant, c'est dans la direction opposée en premier lieu Si vous aimez un programme avec un haut degré d'agrégation, vous pouvez créer une fonction pour chaque fonction. Si vous voulez un programme avec un faible degré de couplage, vous pouvez combiner les fonctions en une seule. Je pense que le changement de paradigme de programmation tel que le type de fonction et l'orientation de l'objet est lié au changement de l'emplacement de ces points médians.

qiita2.PNG

Où avez-vous mis l'orientation de l'aspect?

Je pense que l'orientation objet est un paradigme hautement cohérent Un module est utilisé comme classe, de nombreux modules sont créés et un module est appelé depuis un autre. Cela augmentera le degré de couplage Une technique pour réduire ce degré de couplage est le modèle de conception du GoF. Orienté aspect a un degré élevé de cohésion et un faible degré de cohésion. A commencé

qiita.PNG

** Première idée orientée aspect **

ce843e51-632c-0e74-689d-3affd704ff1c.png

Pourquoi l'orientation des aspects est efficace

Le code qui répond à un besoin de qualité particulier lors de la création de logiciels est souvent dispersé dans la structure modulaire de base du programme. La journalisation est souvent mentionnée à titre d'exemple, et le code qui crache les journaux pour les tests et la sécurité est écrit dans diverses classes (modules). Il s'agit d'une préoccupation transversale, et si elle est transversale plutôt que modulaire, les besoins de qualité peuvent être satisfaits, mais la visibilité globale du programme peut être compromise, ce qui se traduit par une faible efficacité et maintenabilité du développement. y a-t-il La programmation orientée aspect est l'une des techniques efficaces pour la modularisation des préoccupations transversales.

キャプチャ.PNG キャプチャ2.PNG

Quelle est la séparation des préoccupations?

Concern est une classe dans laquelle les processus (méthodes) sont regroupés en termes informatiques. Le principe de la séparation d'un programme en différents modules pour chaque préoccupation est appelé séparation des préoccupations. La séparation consiste à collecter le code lié à chaque préoccupation et à le séparer des autres codes en tant que module indépendant. Différents modules pour différents intérêts facilitent l'extension ou la modification de votre programme L'aspect orienté permet de séparer les intérêts de plusieurs perspectives que l'orientation objet n'était pas possible

AspectJ Une extension du langage Java avec l'ajout d'un paradigme de programmation orienté aspect Les classes et les aspects coexistent, un peu différents de la programmation principale orientée aspect Une méthode de configuration des modules (classes) du point de vue du passé et de les modulariser avec des aspects s'il y a des préoccupations transversales.

Modèle de point de jointure statique pour considérer les points de jointure comme des «lieux» La réflexion sur le «temps» est appelée un modèle de point de jointure dynamique. AspectJ utilise un modèle de point de jointure dynamique

aspect

Être comme une classe en Java En Java, les classes décrivent les membres et les méthodes ensemble, Dans AspectJ, l'aspect décrit ensemble "conseil", "point cut", "déclaration intertype", etc.

Aspect.java


import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before

@Aspect
public class Aspect {
  @before("execution(* hoge.*.*(..))")
  public void before() {
    System.out.println("before!");
  }
}

Aspect.java


public aspect GreetingAspect {
  pointcut message():
    call(* Messenger.printMessage(..));
  before(): message() {
    System.out.print("Hello, ");
  }
}

Coupe en pointe

Le conseil est configuré pour appeler le conseil lorsque la méthode définie est appelée Le point de coupure détermine si l'événement qui s'est produit lors de l'appel de la méthode correspond à l'événement auquel le conseil est associé. (* L'événement ne se produit pas réellement) Pensez-y comme si vous vous inscrivez à un EventListener, par exemple lorsqu'un bouton est cliqué.

qiita4.PNG

Types de coupes ponctuelles

Il existe des coupes ponctuelles dynamiques et des coupes ponctuelles statiques dans les coupes ponctuelles.

** Coupe de points liée à la méthode **

Il y a deux coupures de points liées aux appels de méthode: ** call ** et ** execution **. Il prend un modèle de méthode comme argument et représente le "moment" auquel la méthode est appelée et exécutée.

Sample.java


call(void Main.init())
execution(void Main.init())
//Les deux éléments ci-dessus représentent le moment où la méthode init de la classe Main est appelée.

:black_small_square:call Une série de traitements depuis le moment où le thread d'exécution du programme atteint l'expression d'appel de méthode correspondante jusqu'à ce qu'il exécute le corps de la méthode appelée et retourne à nouveau sur le côté de l'expression d'appel.

:black_small_square:execution Après que le thread d'exécution du programme se déplace dans le corps de la méthode appelée, une série de traitements du début à la fin de l'exécution du corps de la méthode Traitement effectué entre les méthodes sur lesquelles le thread d'exécution est appelé

En général [L'appel sélectionne le "quand" lorsque la méthode est appelée, et l'exécution sélectionne le "quand" lorsque la méthode appelée est exécutée] Il est bon de se souvenir

854af01b-4ded-6512-3166-ba4c68a96d22.png

Différence entre appel et exécution

L'appel d'une méthode non statique à l'aide de super est sélectionné pour l'exécution, mais pas pour l'appel La découpe du point d'appel est sélectionnée en fonction du type superficiel à appeler, tandis que la découpe du point d'exécution est sélectionnée en fonction du type réel de l'objet à appeler.

Setumei.java


/*Partie de classe*/
interface Main {
  public abstract void init();
}
class Sub implements Main {
  public Sub() {

  }
  public void init() {

  }
}

/******************* call ***********************/
/*Partie Aspect*/
call(void Sub.init())

/*Partie exécution*/
Sub sub = new Sub();
Main s = sub;
sub.init();          //Être sélectionné
s.init();            //Non séléctionné
((Main)sub).init();  //Non séléctionné

/************* execution ***********************/


/*Partie Aspect*/
execution(void Sub.init())

/*Partie exécution*/
sub.init();          //Être sélectionné
s.init();            //Être sélectionné
((Main)sub).init();  //Être sélectionné

** Coupe ponctuelle liée au champ **

Il existe deux pointcuts liés au champ, ** get ** et ** set **. Prend un modèle de champ comme argument et représente le "temps" lors de la lecture et de l'écriture du champ

Sample.java


//En se référant à la valeur du champ nommé x dans le type int de la classe Person
get(int Point.x)

//Lorsqu'une valeur est affectée à un champ de n'importe quel nom dont le type de champ non privé de la classe Person est le type String
set(!private String Person.*)

//Lorsqu'une valeur est référencée dans un champ de n'importe quel type et n'importe quel nom déclaré dans n'importe quelle interface de classe
get(* *)

:black_small_square:get Lorsque vous faites référence à (appelez) un champ

:black_small_square:set Lors de l'attribution d'une valeur à un champ

** Coupe ponctuelle liée au constructeur **

Il existe quatre pointcuts liés au champ: ** appel **, ** exécution **, ** initialisation ** et ** préinitialisation **. Prend un modèle de constructeur comme argument et représente le "moment" où un objet est créé avec un constructeur correspondant

Sample.java


call(public Point.new(int, int))
initialization(*.new(..))

:black_small_square:call Lors de l'exécution du nouvel opérateur Jusqu'à ce que le thread d'exécution du programme passe du côté exécutant le nouvel opérateur au corps du constructeur et revienne au côté d'origine une fois l'exécution terminée.

:black_small_square:execution Une fois que les autres appels de constructeur par super ou ceci sont terminés, alors que le premier constructeur appelé est en cours d'exécution Non inclus pendant que d'autres constructeurs appelés par super ou ceci sont en cours d'exécution

:black_small_square:initialization De la fin de l'appel du constructeur par super à la fin du constructeur appelé Contrairement à l'exécution, cela inclut l'appel et l'exécution d'autres constructeurs

:black_small_square:preinitialization Du début du temps du constructeur appelé à juste avant d'exécuter l'appel du constructeur par super Inclut le temps le long du chemin pour lire un autre constructeur avec this et calculer les arguments réels d'un appel avec this ou super

qiita7.PNG

** Point cut lié à la clause catch **

Si une exception est levée pendant l'exécution du programme, toutes les méthodes en cours d'exécution seront abandonnées prématurément Pour éviter cela, try-catch peut être utilisé pour écrire le traitement de récupération à partir d'exceptions dans le programme.

Un gestionnaire est fourni pour la coupure de point liée à la clause catch. Prend un modèle de type comme argument et représente le "moment" où la clause catch est exécutée

Sample.java


//Écrivez le nom de la classe directement ou utilisez des caractères génériques
handler(java.io.IOException+)

** Autres coupes ponctuelles **

Il y a d'autres coupures ponctuelles, mais elles seront plus longues, alors je les ai résumées séparément. Veuillez voir si vous souhaitez spécifier plus en détail Liste des coupes de points pour les coupes de points plus fines

Conseil

C'est une fonction dans un aspect, comme une méthode dans une classe. Le conseil est inséré (tissage) au point de jonction sélectionné dans le point de coupe Le point de jonction représente le "temps" auquel un traitement est exécuté, mais le "temps" n'est pas un moment mais une période. Vous pouvez choisir quand donner des conseils pendant cette période

qiita12.PNG

Comme le montre la figure ci-dessus, il y a un point au point de jonction et il existe plusieurs endroits pour incorporer des conseils.

Type de conseil

Comme expliqué ci-dessus, le type de conseil détermine où tisser

** avant conseil **

Processus à exécuter immédiatement avant (ou au début de) la période représentée par le point de jonction sélectionné.

Exemple de déclaration avant avis

beforeAdvice.java


before(): loggedMethods() {
  System.out.println("** execute doIt() ...");
}

avant que le conseil ne commence par le mot-clé avant Ecrire les arguments de conseil entre parenthèses avant () Écrivez un point arbitraire coupé entre les deux points de before (): et le crochet ondulé de {}

Exemple d'utilisation avant conseil

beforeAdvide.java


pointcut pickup(BookSession bs, int i):
  call(String String.substring(int)) && this(bs) && args(i);

before(BookSession bs, int i): pickup(bs, i) {
  System.out.println("** substring(" + i + ")");
}

pickup Point cut prend un argument, donc le conseil prend également un argument En écrivant avant (BookSession bs, int i), vous pouvez passer l'argument au point coupé. pickup Point cut attribue une valeur appropriée à l'argument pour chaque point de jointure sélectionné. La valeur attribuée peut être traitée comme une variable normale dans le corps de l'avis.

** après avis **

Processus à exécuter immédiatement après (ou à la fin de) l'institution représentée par le point de jonction sélectionné.

après Exemple de déclaration d'avis

afterAdvice.java


after(): loggedMethods() {
  System.out.println("** execute doIt() ...");
}

** après retour des conseils **

Processus qui est exécuté lorsque le processus pour la période représentée par le point de jointure sélectionné se termine normalement. Si une exception est levée au milieu et qu'elle se termine anormalement, elle ne sera pas exécutée.

après avoir renvoyé l'exemple de déclaration d'avis

afterReturningAdvide.java


after() returning (String s):
  call(* *(..)) && within(BookSession)
{
  System.out.println("Returned Normally with " + s); 
}

Après le retour, l'avis peut être utilisé dans le corps de l'avis en extrayant la valeur de retour lorsqu'il se termine normalement.

** après avoir lancé des conseils **

Le processus qui est exécuté lorsque le processus de la période représentée par le point de jointure sélectionné se termine anormalement en lançant une exception.

après avoir lancé un exemple de déclaration de conseil

afterThrowingAdvice.java


after() throwing (IOExecption e):
  call(* *(..)) && within(BookSession)
{
  System.out.println("Threw an exception " + e);
}

L'argument de lancement e est la valeur de l'exception levée et peut être librement utilisé dans le corps de conseil.

** autour des conseils **

Effectué au lieu de traiter toute la durée du point de jonction sélectionné Si le point de jointure appelle la méthode, seul le conseil autour sera exécuté et l'appel de méthode d'origine ne sera pas exécuté du tout. Écrivez return type around (exemple d'argument) '' Le type de retour doit correspondre au type de retour du point de jointure

Utilisez un exemple de conseil autour

Hello.java


aspect Overrider {
  int around(): call(int Hello.say()) {
    System.out.println("Hi");
    return 1;
  }
}

public class Hello {
  public static int say() {
    System.out.println("Hello");
    return 0;
  }
  public static void main(String[] args) {
    int i = say();
    System.out.println(i);
  }
}

Résultat d'exécution

Quand il y a des conseils
Hi
1
Quand il n'y a pas de conseil
Hello
0

Point de jonction

Représente le "moment" auquel certains traitements ont été exécutés L'endroit où le processus original est effectué et le conseil est tissé, sélectionné par la coupe à la pointe. Parfois traduit par une jonction Considérez-le comme un événement qui se produit lors de l'exécution d'un programme

qiita13.PNG

Déclaration d'intertype

Capacité d'Aspect à changer la structure statique d'un programme Vous pouvez déclarer des méthodes et des sensations pour d'autres classes et interfaces, les renommer et modifier d'autres classes pour implémenter de nouvelles interfaces supplémentaires.

Déclaration de membre intertype

Déclaration des membres d'autres classes et interfaces dans un aspect

[Inter] signifie [entre] Déclaration qui s'étend entre les classes et les interfaces et les aspects C'est pourquoi on l'appelle un inter-type.

** Déclaration de méthode intertype **

Les méthodes d'autres classes et interfaces peuvent être déclarées dans l'aspect La différence avec l'écriture d'une déclaration de méthode normale est d'écrire le nom de la classe ou le nom de l'interface dans lequel la méthode est déclarée avant le nom de la méthode. A part ça, c'est presque la même chose, vous pouvez également utiliser ceci

Exemple d'utilisation de la déclaration de méthode intertype

Hello.java


aspect interTypeMethod {
  public void Hello.say() {
    System.out.println("Hi, I'm " + name);
  }
}

public class Hello {
  String name;
  
  Public Hello(String name) {
    this.name = name;
  }
  Public static void main(String[] args) {
    Hello h = new Hello("Taro");
    h.say();
  }
}

Exemple d'exécution

Hi, I'm Taro

Comme vous pouvez le voir dans l'exemple, il est possible d'appeler la méthode say () comme déclaré dans la classe Hello. Dans la méthode say (), même le champ name de la classe Hello est utilisé. Ce n'est pas trop étrange si vous comprenez que la classe Hello est Weaving au moment de la compilation.

** Déclaration de méthode d'intertype à l'interface ** Dans le langage canonique Java, seules les méthodes abstraites peuvent être déclarées dans l'interface Cependant, les déclarations intertypes vous permettent de déclarer des méthodes non abstraites pour une interface.

Hello.java


aspect interTypeMethod {
  public void Greeting.say() {
    System.out.println("Hi, I'm " + name);
  }
}

interface Greeting {

}

public class Hello implements Greeting {
  String name;
  
  Public Hello(String name) {
    this.name = name;
  }
  Public static void main(String[] args) {
    Hello h = new Hello("Taro");
    h.say();
  }
}

Vous pouvez voir que l'aspect interTypeMethod déclare la méthode say () à l'interface Greeting. Cependant, la classe Hello qui implémente l'interface Greeting ne remplace pas la méthode say (). Comme vous pouvez le voir, déclarer une méthode sur une interface avec un aspect signifie déclarer une méthode non statique.

** Déclaration de champ Intertype **

Peut déclarer des champs pour les classes et les interfaces Le langage canonique Java ne permet pas de déclarer des champs non finaux dans une interface, La déclaration d'intertype vous permet de déclarer des champs non finaux

Hello.java


aspect interTypeField {
  private String Hello.name;
}

public class Hello {
  Public Hello(String name) {
    this.name = name;
  }
  public void say() {
    System.out.println("Hi, I'm " + name);
  }
  Public static void main(String[] args) {
    Hello h = new Hello("Taro");
    h.say();
  }
}

** Déclaration du constructeur intertype **

Peut déclarer des constructeurs de classe et d'interface Même avec la déclaration intertype, il n'est pas possible de déclarer le constructeur de l'interface. Il est possible d'utiliser this et super () dans la déclaration du constructeur d'intertype

Hello.java


aspect interTypeField {
  Public Hello.new(String name) {
    this.name = name;
  }
}

public class Hello {
  String name;

  public void say() {
    System.out.println("Hi, I'm " + name);
  }
  Public static void main(String[] args) {
    Hello h = new Hello("Taro");
    h.say();
  }
}

finalement

Merci d'avoir regardé jusqu'à la fin. Je ne suis pas spécialisé dans l'orientation des aspects, donc je pense qu'il y a eu beaucoup d'erreurs. Le contenu de l'enquête est également ancien, donc je pense qu'il y a des différences par rapport à la situation actuelle. Tout le contenu que j'ai choisi cette fois est mon propre jugement et mes propres préjugés. Il existe de nombreuses autres fonctionnalités intéressantes dans AspectJ. Il y a de nombreux changements dans les modificateurs d'accès et l'héritage de classe dans les déclarations intertypes. Je voudrais écrire plus de détails dans un autre article. Merci d'avoir regardé jusqu'à la fin. J'espère que vous lirez cet article et que vous vous intéresserez à l'orientation des aspects. Veuillez noter qu'il existe de nombreuses erreurs et erreurs.

référence

Recommended Posts

Les temps peuvent venir? Programmation orientée aspect, qu'est-ce que le langage AspectJ?
Ce qui est différent du langage PHP. [Remarque]
Quelle est la méthode pluck?
Qu'est-ce que la classe BufferedReader?
À propos du langage de programmation Crystal
A quoi sert le constructeur?
Quelle est la méthode d'initialisation?
'% 02d' Quel est le% de% 2?
Qu'est-ce qu'un extrait de code en programmation?
[Note technique] Qu'est-ce que l'orientation objet?