[JAVA] Die Zeiten können kommen? Aspektorientierte Programmierung, was ist die AspectJ-Sprache?

Einführung

Während des Seminars hatte ich die Gelegenheit, Forschungsergebnisse in meinem Interessengebiet vorzustellen. Es gab keine Artikel, die auch nach verschiedenen Recherchen interessant erschienen, und das einzige, was interessant schien, war die Aspektorientierung. Es ist eine sehr alte Technologie, daher denke ich, dass viele Leute sie bereits kennen oder nicht daran interessiert sind, aber ich fand sie interessant, deshalb möchte ich sie vorstellen. Ich hoffe, jeder, der diesen Artikel gelesen hat, interessiert sich für Aspektorientierung.

Was ist Aspektorientierung?

Eingeführt als postobjektorientiert, die nächste Technologie nach objektorientiert Dies ist jedoch nicht der Fall. Die Aspektorientierung ist eine Technologie, die die ** Grenzen ** der Objektorientierung ausfüllt und weiterentwickelt.

An erster Stelle in der Softwareentwicklung

In Software ist es gut, dass der Aggregationsgrad hoch und der Bindungsgrad niedrig ist. Dies ist jedoch in erster Linie in die entgegengesetzte Richtung. Wenn Sie ein Programm mit einem hohen Aggregationsgrad mögen, können Sie für jede Funktion eine Funktion erstellen. Wenn Sie ein Programm mit geringem Kopplungsgrad wünschen, können Sie die Funktionen zu einem kombinieren. Ich denke, dass die Änderung des Programmierparadigmas wie Funktionstyp und Objektorientierung mit der Änderung der Position dieser Mittelpunkte zusammenhängt.

qiita2.PNG

Wo haben Sie die Aspektorientierung hingelegt?

Ich denke, Objektorientierung ist ein sehr zusammenhängendes Paradigma Ein Modul wird als Klasse verwendet, viele Module werden erstellt und ein Modul wird von einem anderen aufgerufen. Dies erhöht den Kopplungsgrad Eine Technik zur Reduzierung dieses Kopplungsgrades ist das GoF-Entwurfsmuster. Aspektorientiert hat einen hohen Kohäsionsgrad und einen niedrigen Kohäsionsgrad. Wurde gestartet

qiita.PNG

** Aspektorientierte erste Idee **

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

Warum Aspektorientierung effektiv ist

Der Code, der zur Erfüllung eines bestimmten Qualitätsbedarfs beim Erstellen von Software verwendet wird, ist häufig über die modulare Grundstruktur eines Programms verteilt. Die Protokollierung wird häufig als Beispiel genannt, und der Code, der Protokolle zum Testen und zur Sicherheit ausspuckt, wird in verschiedenen Klassen (Modulen) geschrieben. Dies ist ein Querschnittsthema, und wenn der Querschnitt nicht modularisiert bleibt, können die Qualitätsanforderungen erfüllt werden, aber die Sichtbarkeit des Gesamtprogramms kann beeinträchtigt werden, was zu einer schlechten Entwicklungseffizienz und Wartbarkeit führt. Gibt es Aspektorientierte Programmierung ist eine der effektiven Techniken zur Modularisierung von Querschnittsthemen.

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

Was ist die Trennung von Bedenken?

Sorge ist eine Klasse, in der Prozesse (Methoden) in Informatikbegriffen zusammengefasst werden. Das Prinzip, ein Programm für jedes Unternehmen in verschiedene Module zu unterteilen, wird als Trennung von Bedenken bezeichnet. Bei der Trennung wird der Code für jedes Unternehmen gesammelt und als unabhängiges Modul von anderen Codes getrennt. Verschiedene Module für unterschiedliche Interessen erleichtern das Erweitern oder Ändern Ihres Programms Aspektorientiert ermöglicht die Trennung von Interessen aus mehreren Perspektiven, die objektorientiert nicht möglich waren

AspectJ Eine Erweiterung der Java-Sprache um ein aspektorientiertes Programmierparadigma Klassen und Aspekte existieren nebeneinander, ein wenig anders als die aspektorientierte Hauptprogrammierung Eine Methode, um Module (Klassen) aus der Perspektive der Vergangenheit zu konfigurieren und sie mit Aspekten zu modularisieren, wenn Querschnittsthemen bestehen.

Statisches Verbindungspunktmodell, um Verbindungspunkte als "Orte" zu betrachten. Das Denken an "Zeit" wird als dynamisches Verbindungspunktmodell bezeichnet. AspectJ verwendet ein dynamisches Joinpoint-Modell

Aspekt

In Java wie eine Klasse sein In Java beschreiben Klassen Mitglieder und Methoden zusammen. In AspektJ beschreibt der Aspekt "Beratung", "Punktschnitt", "Intertypdeklaration" usw. zusammen.

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, ");
  }
}

Punktschnitt

Advice ist so eingestellt, dass beim Aufruf der set-Methode die Beratung aufgerufen wird Der Punktschnitt bestimmt, ob das Ereignis, das beim Aufruf der Methode aufgetreten ist, mit dem Ereignis übereinstimmt, dem der Hinweis zugeordnet ist. (* Das Ereignis tritt nicht tatsächlich auf) Stellen Sie sich vor, Sie registrieren sich bei einem EventListener, z. B. wenn Sie auf eine Schaltfläche klicken.

qiita4.PNG

Arten von Punktschnitten

Es gibt dynamische Punktschnitte und statische Punktschnitte in Punktschnitten.

** Methodenbezogener Punktschnitt **

Es gibt zwei Punktschnitte im Zusammenhang mit Methodenaufrufen: ** Aufruf ** und ** Ausführung **. Es nimmt ein Methodenmuster als Argument und repräsentiert die "Zeit", zu der die Methode aufgerufen und ausgeführt wird.

Sample.java


call(void Main.init())
execution(void Main.init())
//Beide oben genannten Werte geben an, wann die init-Methode der Main-Klasse aufgerufen wird.

:black_small_square:call Eine Reihe von Verarbeitungen von dem Zeitpunkt, an dem der Ausführungsthread des Programms den entsprechenden Methodenaufrufausdruck erreicht, bis zu dem Zeitpunkt, an dem er den Hauptteil der aufgerufenen Methode ausführt und wieder zur Seite des Aufrufausdrucks zurückkehrt.

:black_small_square:execution Nachdem der Ausführungsthread des Programms in den Hauptteil der aufgerufenen Methode verschoben wurde, erfolgt eine Reihe von Verarbeitungen vom Anfang bis zum Ende der Ausführung des Methodenkörpers Die Verarbeitung erfolgt zwischen den Methoden, für die der Ausführungsthread aufgerufen wird

Im Allgemeinen [Aufruf wählt das "Wann" aus, wenn die Methode aufgerufen wird, und Ausführung wählt das "Wann" aus, wenn die aufgerufene Methode ausgeführt wird] Es ist gut, sich zu erinnern

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

Unterschied zwischen Aufruf und Ausführung

Das Aufrufen einer nicht statischen Methode mit super wird für die Ausführung ausgewählt, nicht jedoch für den Aufruf Aufrufpunktschnitte werden basierend auf dem aufgerufenen Oberflächentyp ausgewählt, während Ausführungspunktschnitte basierend auf dem wahren Typ des aufgerufenen Objekts ausgewählt werden.

Setumei.java


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

  }
  public void init() {

  }
}

/******************* call ***********************/
/*Aspektteil*/
call(void Sub.init())

/*Ausführungsteil*/
Sub sub = new Sub();
Main s = sub;
sub.init();          //Ausgewählt werden
s.init();            //Nicht ausgewählt
((Main)sub).init();  //Nicht ausgewählt

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


/*Aspektteil*/
execution(void Sub.init())

/*Ausführungsteil*/
sub.init();          //Ausgewählt werden
s.init();            //Ausgewählt werden
((Main)sub).init();  //Ausgewählt werden

** Feldbezogener Punktschnitt **

Es gibt zwei feldbezogene Punktschnitte, ** get ** und ** set **. Es nimmt ein Feldmuster als Argument und repräsentiert die "Zeit", zu der das Feld gelesen oder geschrieben wird.

Sample.java


//Wenn Sie sich auf den Wert des Felds mit dem Namen x im int-Typ der Person-Klasse beziehen
get(int Point.x)

//Wenn einem Feld eines beliebigen Namens ein Wert zugewiesen wird, dessen nicht privater Feldtyp der Person-Klasse der String-Typ ist
set(!private String Person.*)

//Wenn auf einen Wert in einem Feld eines beliebigen Typs verwiesen wird und ein beliebiger Name in einer Klassenschnittstelle deklariert ist
get(* *)

:black_small_square:get Wenn Sie sich auf ein Feld beziehen (es aufrufen)

:black_small_square:set Wenn Sie einem Feld einen Wert zuweisen

** Konstruktorbezogener Punktschnitt **

Es gibt vier feldbezogene Punktschnitte: ** Aufruf **, ** Ausführung **, ** Initialisierung ** und ** Vorinitialisierung **. Nimmt ein Konstruktormuster als Argument und stellt die "Zeit" dar, zu der ein Objekt mit einem passenden Konstruktor erstellt wird

Sample.java


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

:black_small_square:call Während der Ausführung des neuen Operators Bis sich der Ausführungsthread des Programms von der Seite, auf der der neue Operator ausgeführt wird, zum Hauptteil des Konstruktors bewegt und nach Abschluss der Ausführung wieder zur ursprünglichen Seite zurückkehrt.

:black_small_square:execution Nachdem die anderen Konstruktoraufrufe von super oder dies beendet wurden, während der erste aufgerufene Konstruktor tatsächlich ausgeführt wird Nicht enthalten, während andere von super aufgerufene Konstruktoren ausgeführt werden

:black_small_square:initialization Vom Ende des Konstruktoraufrufs von super bis zum Ende des aufgerufenen Konstruktors Im Gegensatz zur Ausführung umfasst dies das Aufrufen und Ausführen anderer Konstruktoren

:black_small_square:preinitialization Vom Beginn der aufgerufenen Konstruktorzeit bis kurz vor der Ausführung des Konstruktoraufrufs durch super Beinhaltet Zeit auf dem Weg, um einen anderen Konstruktor damit zu lesen und die tatsächlichen Argumente eines Aufrufs mit diesem oder super zu berechnen

qiita7.PNG

** Punktschnitt im Zusammenhang mit der Fangklausel **

Wenn während der Ausführung des Programms eine Ausnahme ausgelöst wird, werden alle laufenden Methoden vorzeitig abgebrochen Um dies zu vermeiden, kann try-catch verwendet werden, um die Wiederherstellungsverarbeitung aus Ausnahmen im Programm zu schreiben.

Für den Punktschnitt im Zusammenhang mit der catch-Klausel wird ein Handler bereitgestellt. Nimmt ein Typmuster als Argument und repräsentiert die "Zeit", zu der die catch-Klausel ausgeführt wird

Sample.java


//Schreiben Sie den Klassennamen direkt oder verwenden Sie Platzhalter
handler(java.io.IOException+)

** Andere Punktschnitte **

Es gibt andere Punktschnitte, aber sie werden länger sein, deshalb habe ich sie separat zusammengefasst. Bitte sehen Sie, ob Sie genauer angeben möchten Liste der Punktschnitte für feinere Punktschnitte

Rat

Es ist eine Funktion in einem Aspekt, wie eine Methode in einer Klasse. Der Hinweis wird an dem im Punktschnitt ausgewählten Verbindungspunkt eingefügt (gewebt) Der Verknüpfungspunkt stellt die "Zeit" dar, zu der eine Verarbeitung ausgeführt wird, aber die "Zeit" ist kein Moment, sondern eine Periode. Sie können wählen, wann Sie in diesem Zeitraum Ratschläge geben möchten

qiita12.PNG

Wie in der obigen Abbildung gezeigt, gibt es am Verbindungspunkt einen Punkt, und es gibt mehrere Stellen, an denen Ratschläge eingefügt werden können.

Art von Rat

Wie oben erläutert, bestimmt die Art der Beratung, wo gewebt werden soll

** vor Beratung **

Der Prozess, der unmittelbar vor (oder zu Beginn) der durch den ausgewählten Verknüpfungspunkt dargestellten Periode ausgeführt werden soll.

Beispiel für eine Voraberklärung

beforeAdvice.java


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

Bevor der Rat mit dem Schlüsselwort beginnt Schreiben Sie Ratschläge in Klammern vor () Schreiben Sie einen beliebigen Punkt zwischen dem Doppelpunkt von before (): und der wellenförmigen Klammer von {}

Beispiel für die Verwendung vor Beratung

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 braucht ein Argument, also braucht der Rat auch ein Argument Wenn Sie vorher schreiben (BookSession bs, int i), können Sie das Argument an den Punktschnitt übergeben. pickup Point cut weist dem Argument für jeden ausgewählten Verbindungspunkt einen geeigneten Wert zu. Der zugewiesene Wert kann wie eine normale Variable im Hauptteil des Hinweises behandelt werden.

** nach Beratung **

Der Prozess, der unmittelbar nach (oder am Ende) der Institution ausgeführt werden soll, die durch den ausgewählten Verknüpfungspunkt dargestellt wird.

nach Beispiel Beratungserklärung

afterAdvice.java


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

** nach Rücksendung **

Der Prozess, der ausgeführt wird, wenn der Prozess des durch den ausgewählten Verknüpfungspunkt dargestellten Zeitraums normal endet. Wenn eine Ausnahme in der Mitte ausgelöst wird und abnormal beendet wird, wird sie nicht ausgeführt.

nach Rückgabe Beispiel für die Deklaration

afterReturningAdvide.java


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

Nach der Rücksendung können Ratschläge im Hauptteil der Ratschläge verwendet werden, indem der Rückgabewert extrahiert wird, wenn er normal endet.

** nach dem Werfen Rat **

Die Verarbeitung, die ausgeführt wird, wenn die Verarbeitung für den durch den ausgewählten Verknüpfungspunkt dargestellten Zeitraum abnormal endet, indem eine Ausnahme ausgelöst wird

nach dem Werfen Ratgeber Beispiel

afterThrowingAdvice.java


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

Das Auslöseargument e ist der Wert der ausgelösten Ausnahme und kann im Beratungsgremium frei verwendet werden.

** um Rat **

Wird ausgeführt, anstatt die gesamte Dauer des ausgewählten Verknüpfungspunkts zu verarbeiten Wenn der Join-Punkt die Methode aufruft, wird nur der Around-Hinweis ausgeführt, und der ursprüngliche Methodenaufruf wird überhaupt nicht ausgeführt. Schreiben Sie `Rückgabetyp um (Beispielargument)` Der Rückgabetyp muss mit dem Rückgabetyp des Verknüpfungspunkts übereinstimmen

Verwenden Sie ein Beispiel für Ratschläge

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);
  }
}

Ausführungsergebnis

Wenn es um Ratschläge geht
Hi
1
Wenn es keinen Rat gibt
Hello
0

Verbindungspunkt

Stellt die "Zeit" dar, zu der eine Verarbeitung ausgeführt wurde Der Ort, an dem der ursprüngliche Prozess ausgeführt und der Rat gewebt wird, ausgewählt durch den Punktschnitt. Manchmal als Kreuzung übersetzt Stellen Sie sich das als ein Ereignis vor, das während der Ausführung eines Programms auftritt

qiita13.PNG

Intertype-Deklaration

Die Fähigkeit von Aspect, die statische Struktur eines Programms zu ändern Sie können Methoden und Gefühle für andere Klassen und Schnittstellen deklarieren, umbenennen und andere Klassen ändern, um zusätzliche neue Schnittstellen zu implementieren.

Intertype-Mitgliederdeklaration

Deklarieren von Mitgliedern anderer Klassen und Schnittstellen in einem Aspekt

[Inter] bedeutet [zwischen] Erklärung, die sich zwischen Klassen, Schnittstellen und Aspekten erstreckt Deshalb wird es als Inter-Typ bezeichnet.

** Deklaration der Intertype-Methode **

Methoden anderer Klassen und Schnittstellen können innerhalb des Aspekts deklariert werden Der Unterschied zum Schreiben einer normalen Methodendeklaration besteht darin, den Klassennamen oder den Schnittstellennamen, in dem die Methode deklariert ist, vor den Methodennamen zu schreiben. Davon abgesehen ist es fast dasselbe, Sie können dies auch verwenden

Beispiel für die Verwendung der Intertype-Methodendeklaration

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();
  }
}

Ausführungsbeispiel

Hi, I'm Taro

Wie Sie im Beispiel sehen können, ist es möglich, die in der Hello-Klasse deklarierte say () -Methode aufzurufen. In der say () -Methode wird sogar das Namensfeld der Hello-Klasse verwendet. Es ist nicht allzu seltsam, wenn Sie verstehen, dass die Hello-Klasse zur Kompilierungszeit gewebt wird.

** Deklaration der Intertype-Methode an die Schnittstelle ** In der kanonischen Java-Sprache können nur abstrakte Methoden in der Schnittstelle deklariert werden Mit Intertype-Deklarationen können Sie jedoch nicht abstrakte Methoden für eine Schnittstelle deklarieren.

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();
  }
}

Sie können sehen, dass der Aspekt interTypeMethod die Methode say () für die Begrüßungsschnittstelle deklariert. Die Hello-Klasse, die die Begrüßungsschnittstelle implementiert, überschreibt jedoch nicht die say () -Methode. Wie Sie sehen können, bedeutet das Deklarieren einer Methode auf einer Schnittstelle mit einem Aspekt das Deklarieren einer nicht statischen Methode.

** Intertype-Felddeklaration **

Kann Felder für Klassen und Schnittstellen deklarieren In der kanonischen Java-Sprache können Sie keine nicht endgültigen Felder in einer Schnittstelle deklarieren. Mit der Intertype-Deklaration können Sie nicht endgültige Felder deklarieren

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();
  }
}

** Intertyp-Konstruktordeklaration **

Kann Klassen- und Schnittstellenkonstruktoren deklarieren Selbst mit der Intertype-Deklaration ist es nicht möglich, den Konstruktor der Schnittstelle zu deklarieren. Es ist möglich, dies und super () in der Intertyp-Konstruktordeklaration zu verwenden

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();
  }
}

Schließlich

Danke, dass du bis zum Ende zugesehen hast. Ich bin nicht auf Aspektorientierung spezialisiert, daher denke ich, dass es viele Fehler gab. Der Inhalt der Untersuchung ist ebenfalls alt, daher denke ich, dass es einige Unterschiede zur aktuellen Situation gibt. Alles, was ich dieses Mal gewählt habe, ist mein eigenes Urteilsvermögen und Vorurteil. Es gibt viele andere großartige Funktionen in AspectJ. Es gibt viele Änderungen bei Zugriffsmodifikatoren und Klassenvererbung in Intertypdeklarationen. Ich möchte mehr Details in einem anderen Artikel schreiben. Danke, dass du bis zum Ende zugesehen hast. Ich hoffe, Sie lesen diesen Artikel und interessieren sich für Aspektorientierung. Bitte beachten Sie, dass es viele Fehler und Irrtümer gibt.

Referenz

Recommended Posts

Die Zeiten können kommen? Aspektorientierte Programmierung, was ist die AspectJ-Sprache?
Was unterscheidet sich von der PHP-Sprache. [Hinweis]
Was ist die Zupfmethode?
Was ist die BufferedReader-Klasse?
Über die Programmiersprache Crystal
Wofür ist der Konstruktor?
Was ist die Initialisierungsmethode?
'% 02d' Was ist der% von% 2?
Was ist ein Ausschnitt in der Programmierung?
[Technischer Hinweis] Was ist objektorientiert?