Heim Java javaLernprogramm Verwenden von Annotationen in Java zum Erstellen einer Strategie

Verwenden von Annotationen in Java zum Erstellen einer Strategie

Jan 10, 2025 pm 12:13 PM

Usando annotations em Java para fazer um strategy

Ich habe eine sehr interessante Situation bei der Arbeit erlebt und möchte hier die Lösung mitteilen.

Stellen Sie sich vor, Sie müssen eine Reihe von Daten verarbeiten. Und um mit diesem Datensatz umzugehen, gibt es verschiedene Strategien. Ich musste beispielsweise Strategien erstellen, wie eine Datensammlung aus S3 oder Beispiele aus dem lokalen Repository abgerufen oder als Eingabe übergeben werden.

Und wer auch immer diese Strategie diktiert, ist derjenige, der die Anfrage stellt:

Ich möchte die Daten in S3 erhalten. Nehmen Sie die am Tag X zwischen den Stunden H1 und H2 generierten Daten, die vom Abóbora-Client stammen. Holen Sie sich die letzten 3000 Daten, die dies erfüllen.

Oder:

Nehmen Sie die Beispieldaten, die Sie dort haben, und kopieren Sie sie 10.000 Mal, um den Stresstest durchzuführen.

Oder sogar:

Ich habe dieses Verzeichnis, Sie haben auch Zugriff darauf. Holen Sie sich alles in diesem Verzeichnis und rekursiv in die Unterverzeichnisse.

Und schließlich auch:

Nehmen Sie diese Dateneinheit, die sich in der Eingabe befindet, und verwenden Sie sie.

Wie umsetzen?

Mein erster Gedanke war: „Wie kann ich die Form meiner Eingabe in Java definieren?“

Und ich kam zu der ersten Schlussfolgerung, die für das Projekt super wichtig ist: „Weißt du was? Ich werde keine Form definieren. Füge eine Map hinzu, die damit umgehen kann.“

Da ich außerdem keine Formen in das DTO eingefügt habe, hatte ich völlige Freiheit, mit der Eingabe zu experimentieren.

Nachdem wir einen Proof of Concept erstellt haben, kommen wir zu der Situation: Wir müssen aus dem Stress-POC herauskommen und zu etwas übergehen, das einem echten Nutzen nahekommt.

Der Dienst, den ich leistete, bestand darin, Regeln zu validieren. Grundsätzlich musste ich beim Ändern einer Regel diese Regel mit den Ereignissen vergleichen, die in der Produktionsanwendung aufgetreten sind. Oder wenn die Anwendung geändert wurde und keine Fehler aufgetreten sind, wird erwartet, dass die Entscheidung für dieselbe Regel für dieselben Daten dieselbe bleibt; Wenn nun die Entscheidung für dieselbe Regel, die denselben Datensatz verwendet, geändert wird ... nun, das kann zu Problemen führen.

Also brauchte ich diese Anwendung, um das Backtesting der Regeln durchzuführen. Ich muss die reale Anwendung aufrufen, die die Daten zur Auswertung und die betreffende Regel sendet. Die Verwendung hierfür ist sehr vielfältig:

  • Validieren Sie mögliche Abweichungen bei der Aktualisierung der Anwendung
  • Überprüfen Sie, ob die geänderten Regeln das gleiche Verhalten beibehalten
    • zum Beispiel die Optimierung der Regelausführungszeit
  • Überprüfen Sie, ob die Änderung der Regeln zu der erwarteten Änderung der Entscheidungen geführt hat
  • Bestätigen Sie, dass die Anwendung durch die Änderung tatsächlich effizienter geworden ist
    • Wenn ich beispielsweise die neue Version von GraalVM mit aktiviertem JVMCI verwende, erhöht sich die Anzahl der Anfragen, die ich stellen kann?

Dafür brauche ich also einige Strategien für die Entstehung von Ereignissen:

  • Holen Sie sich die echten Daten von S3
  • Nehmen Sie die Daten, die sich als Beispiel im Repository befinden, und kopieren Sie sie mehrmals
  • rufen Sie die Daten von einem bestimmten Ort auf meinem lokalen Computer ab

Und ich brauche auch Strategien, die von meinen Regeln abweichen:

  • per Eingabe übergeben
  • verwendet den schnell laufenden Stub
  • verwendet eine Stichprobe basierend auf der Produktionsregel
  • Verwenden Sie diesen Pfad hier auf meinem Computer

Wie gehe ich damit um? Nun, lassen Sie den Benutzer die Daten bereitstellen!

Die API für Strategie

Wissen Sie etwas, das meine Aufmerksamkeit immer auf JSON-Schema gelenkt hat? Das hier:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://json-schema.org/draft/2020-12/schema",
    "$vocabulary": {
        //...
    }
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Diese Felder beginnen mit $. Meiner Meinung nach werden sie zur Angabe von Metadaten verwendet. Warum also nicht dies in der Dateneingabe verwenden, um die Metadaten der verwendeten Strategie anzugeben?

{
    "dados": {
        "$strategy": "sample",
        "copias": 15000
    },
    //...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Zum Beispiel kann ich 15000 Exemplare meiner Daten als Muster bestellen. Oder fordern Sie einige Dinge von S3 an, indem Sie eine Abfrage in Athena durchführen:

{
    "dados": {
        "$strategy": "athena-query",
        "limit": 15000,
        "inicio": "2024-11-25",
        "fim": "2024-11-26",
        "cliente": "Abóbora"
    },
    //...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Oder im lokalen Pfad?

{
    "dados": {
        "$strategy": "localpath",
        "cwd": "/home/jeffque/random-project-file",
        "dir": "../payloads/esses-daqui/top10-hard/"
    },
    //...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Und so kann ich die Auswahl der bevorstehenden Strategie delegieren.

Codeüberprüfung und die Fassade

Mein erster Ansatz im Umgang mit Strategien war dieser:

public DataLoader getDataLoader(Map<String, Object> inputDados) {
    final var strategy = (String) inputDados.get("$strategy");
    return switch (strategy) {
        case "localpath" -> new LocalpathDataLoader();
        case "sample" -> new SampleDataLoader(resourcePatternResolver_spring);
        case "athena-query" -> new AthenaQueryDataLoader(athenaClient, s3Client);
        default -> new AthenaQueryDataLoader(athenaClient, s3Client);
    }
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Also stellte mein Architekt während der Codeüberprüfung zwei Fragen:

  • „Warum instanziieren Sie alles und lassen den Frühling nicht für sich arbeiten?“
  • Er hat eine DataLoaderFacade im Code erstellt und sie halbfertig aufgegeben

Was habe ich daraus verstanden? Dass es eine gute Idee wäre, die Fassade zu nutzen, um die Verarbeitung an die richtige Ecke zu delegieren und... die manuelle Kontrolle aufzugeben?

Nun, durch den Frühling passiert viel Magie. Da wir in einem Java-Haus mit Java-Expertise sind, warum nicht das idiomatische Java/Spring verwenden, oder? Nur weil ich als Einzelperson manche Dinge schwer zu verstehen finde, heißt das nicht zwangsläufig, dass sie kompliziert sind. Lassen Sie uns also in die Welt der Java-Abhängigkeitsinjektionsmagie eintauchen.

Erstellen des Objekts Fassade

Was früher war:

final var dataLoader = getDataLoader(inputDados)
dataLoader.loadData(inputDados, workingPath);
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Wurde:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://json-schema.org/draft/2020-12/schema",
    "$vocabulary": {
        //...
    }
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Meine Controller-Ebene muss dies also nicht verwalten. Überlassen Sie es der Fassade.

Also, wie machen wir die Fassade? Nun, um zu beginnen, muss ich alle Objekte hinein injizieren:

{
    "dados": {
        "$strategy": "sample",
        "copias": 15000
    },
    //...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Ok, für den Haupt-DataLoader schreibe ich ihn zusätzlich zu @Service als @Primary. Den Rest schreibe ich einfach mit @Service auf.

Testen Sie dies hier, indem Sie getDataLoader so einstellen, dass es null zurückgibt, nur um auszuprobieren, wie Spring den Konstruktor aufruft, und ... es hat funktioniert. Jetzt muss ich notieren mit Metadaten für jeden Dienst, welche Strategie er verwendet...

Wie geht das...

Nun, schauen Sie! In Java haben wir Annotationen! Ich kann eine Laufzeit-Annotation erstellen, die enthält, welche Strategien von dieser Komponente verwendet werden!

Damit ich so etwas in AthenaQueryDataLoader haben kann:

{
    "dados": {
        "$strategy": "athena-query",
        "limit": 15000,
        "inicio": "2024-11-25",
        "fim": "2024-11-26",
        "cliente": "Abóbora"
    },
    //...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Und ich kann auch Aliase haben, warum nicht?

{
    "dados": {
        "$strategy": "localpath",
        "cwd": "/home/jeffque/random-project-file",
        "dir": "../payloads/esses-daqui/top10-hard/"
    },
    //...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Und zeigen!

Aber wie erstellt man diese Anmerkung? Nun, ich brauche ein Attribut, das ein Vektor aus Zeichenfolgen ist (der Java-Compiler kümmert sich bereits um die Bereitstellung einer einzelnen Zeichenfolge und deren Umwandlung in einen Vektor mit einer Position). Der Standardwert ist value. Es sieht so aus:

public DataLoader getDataLoader(Map<String, Object> inputDados) {
    final var strategy = (String) inputDados.get("$strategy");
    return switch (strategy) {
        case "localpath" -> new LocalpathDataLoader();
        case "sample" -> new SampleDataLoader(resourcePatternResolver_spring);
        case "athena-query" -> new AthenaQueryDataLoader(athenaClient, s3Client);
        default -> new AthenaQueryDataLoader(athenaClient, s3Client);
    }
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Wenn das Anmerkungsfeld keinen Wert hätte, müsste ich es explizit machen, und das würde hässlich aussehen, wie in der EstrategiaFeia-Anmerkung:

final var dataLoader = getDataLoader(inputDados)
dataLoader.loadData(inputDados, workingPath);
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Meiner Meinung nach klingt es nicht so natürlich.

Okay, in Anbetracht dessen brauchen wir noch:

  • Klassenanmerkungen aus übergebenen Objekten extrahieren
  • Erstellen Sie eine String-Map Rechtspfeil Datenlader (oder string Rechtspfeil T)

Extrahieren der Anmerkung und Zusammenstellen der Karte

Um die Anmerkung zu extrahieren, muss ich Zugriff auf die Objektklasse haben:

dataLoaderFacade.loadData(inputDados, workingPath);
Nach dem Login kopieren
Nach dem Login kopieren

Darf ich außerdem fragen, ob dieser Kurs mit einer Anmerkung wie „Strategie:“ versehen wurde?

@Service // para o Spring gerenciar esse componente como um serviço
public class DataLoaderFacade implements DataLoader {

    public DataLoaderFacade(DataLoader primaryDataLoader,
                            List<DataLoader> dataLoaderWithStrategies) {
        // armazena de algum modo
    }

    @Override
    public CompletableFuture<Void> loadData(Map<String, Object> input, Path workingPath) {
        return getDataLoader(input).loadData(input, workingPath);
    }

    private DataLoader getDataLoader(Map<String, Object> input) {
        final var strategy = input.get("$strategy");
        // magia...
    }
}
Nach dem Login kopieren
Nach dem Login kopieren

Erinnern Sie sich, dass es das Wertefeld gibt? Nun, dieses Feld gibt einen Vektor von Zeichenfolgen zurück:

@Service
@Primary
@Estrategia("athena-query")
public class AthenaQueryDataLoader implements DataLoader {
    // ...
}
Nach dem Login kopieren

Zeigen! Aber ich stehe vor einer Herausforderung, denn vorher hatte ich ein Objekt vom Typ T und jetzt möchte ich dasselbe Objekt in (T, String)[] abbilden. In Streams ist die klassische Operation, die dies tut, flatMap. Und Java erlaubt mir auch nicht, so ein Tupel aus dem Nichts zurückzugeben, aber ich kann damit einen Datensatz erstellen.

Es würde ungefähr so ​​aussehen:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://json-schema.org/draft/2020-12/schema",
    "$vocabulary": {
        //...
    }
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Was ist, wenn es ein Objekt gibt, das nicht mit einer Strategie versehen wurde? Wird es NPE geben? Besser nicht, lass es uns vor der NPE herausfiltern:

{
    "dados": {
        "$strategy": "sample",
        "copias": 15000
    },
    //...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Vor diesem Hintergrund muss ich noch eine Karte zusammenstellen. Und siehe da: Java stellt hierfür bereits einen Collector zur Verfügung! Collector.toMap(keyMapper, valueMapper)

{
    "dados": {
        "$strategy": "athena-query",
        "limit": 15000,
        "inicio": "2024-11-25",
        "fim": "2024-11-26",
        "cliente": "Abóbora"
    },
    //...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Bis jetzt ok. Aber flatMap hat mich besonders gestört. Es gibt eine neue Java-API namens mapMulti, die dieses Potenzial zur Vervielfältigung bietet:

{
    "dados": {
        "$strategy": "localpath",
        "cwd": "/home/jeffque/random-project-file",
        "dir": "../payloads/esses-daqui/top10-hard/"
    },
    //...
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Schönheit. Ich habe es für DataLoader bekommen, aber ich muss das Gleiche auch für RuleLoader tun. Oder vielleicht auch nicht? Wie Sie bemerken, enthält dieser Code nichts, was spezifisch für DataLoader ist. Wir können diesen Code abstrahieren!!

public DataLoader getDataLoader(Map<String, Object> inputDados) {
    final var strategy = (String) inputDados.get("$strategy");
    return switch (strategy) {
        case "localpath" -> new LocalpathDataLoader();
        case "sample" -> new SampleDataLoader(resourcePatternResolver_spring);
        case "athena-query" -> new AthenaQueryDataLoader(athenaClient, s3Client);
        default -> new AthenaQueryDataLoader(athenaClient, s3Client);
    }
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Unter der Fassade

Aus rein praktischen Gründen habe ich diesen Algorithmus in die Anmerkung eingefügt:

final var dataLoader = getDataLoader(inputDados)
dataLoader.loadData(inputDados, workingPath);
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Und für die Fassade? Nun, es ist gut, das Gleiche zu sagen. Ich habe beschlossen, Folgendes zu abstrahieren:

dataLoaderFacade.loadData(inputDados, workingPath);
Nach dem Login kopieren
Nach dem Login kopieren

Und die Fassade sieht so aus:

@Service // para o Spring gerenciar esse componente como um serviço
public class DataLoaderFacade implements DataLoader {

    public DataLoaderFacade(DataLoader primaryDataLoader,
                            List<DataLoader> dataLoaderWithStrategies) {
        // armazena de algum modo
    }

    @Override
    public CompletableFuture<Void> loadData(Map<String, Object> input, Path workingPath) {
        return getDataLoader(input).loadData(input, workingPath);
    }

    private DataLoader getDataLoader(Map<String, Object> input) {
        final var strategy = input.get("$strategy");
        // magia...
    }
}
Nach dem Login kopieren
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonVerwenden von Annotationen in Java zum Erstellen einer Strategie. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

Video Face Swap

Video Face Swap

Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Verursacht die Sicherheitssoftware des Unternehmens, die die Anwendung nicht ausführt? Wie kann man es beheben und es lösen? Verursacht die Sicherheitssoftware des Unternehmens, die die Anwendung nicht ausführt? Wie kann man es beheben und es lösen? Apr 19, 2025 pm 04:51 PM

Fehlerbehebung und Lösungen für die Sicherheitssoftware des Unternehmens, die dazu führt, dass einige Anwendungen nicht ordnungsgemäß funktionieren. Viele Unternehmen werden Sicherheitssoftware bereitstellen, um die interne Netzwerksicherheit zu gewährleisten. ...

Wie vereinfachte ich Probleme mit der Feldzuordnung im Systemdocking mithilfe des Mapstruct? Wie vereinfachte ich Probleme mit der Feldzuordnung im Systemdocking mithilfe des Mapstruct? Apr 19, 2025 pm 06:21 PM

Die Verarbeitung von Feldzuordnungen im Systemdocken stößt häufig auf ein schwieriges Problem bei der Durchführung von Systemdocken: So kartieren Sie die Schnittstellenfelder des Systems und ...

Wie kann ich elegante Entitätsklassenvariablennamen erhalten, um Datenbankabfragebedingungen zu erstellen? Wie kann ich elegante Entitätsklassenvariablennamen erhalten, um Datenbankabfragebedingungen zu erstellen? Apr 19, 2025 pm 11:42 PM

Bei Verwendung von MyBatis-Plus oder anderen ORM-Frameworks für Datenbankvorgänge müssen häufig Abfragebedingungen basierend auf dem Attributnamen der Entitätsklasse erstellt werden. Wenn Sie jedes Mal manuell ...

Wie konvertiere ich Namen in Zahlen, um die Sortierung zu implementieren und die Konsistenz in Gruppen aufrechtzuerhalten? Wie konvertiere ich Namen in Zahlen, um die Sortierung zu implementieren und die Konsistenz in Gruppen aufrechtzuerhalten? Apr 19, 2025 pm 11:30 PM

Lösungen zum Umwandeln von Namen in Zahlen zur Implementierung der Sortierung in vielen Anwendungsszenarien müssen Benutzer möglicherweise in Gruppen sortieren, insbesondere in einem ...

Wie identifiziert Intellij IDEA die Portnummer eines Spring -Boot -Projekts, ohne ein Protokoll auszugeben? Wie identifiziert Intellij IDEA die Portnummer eines Spring -Boot -Projekts, ohne ein Protokoll auszugeben? Apr 19, 2025 pm 11:45 PM

Beginnen Sie den Frühling mit der Intellijideaultimate -Version ...

Wie kann ich Java -Objekte sicher in Arrays umwandeln? Wie kann ich Java -Objekte sicher in Arrays umwandeln? Apr 19, 2025 pm 11:33 PM

Konvertierung von Java-Objekten und -Arrays: Eingehende Diskussion der Risiken und korrekten Methoden zur Konvertierung des Guss-Typs Viele Java-Anfänger werden auf die Umwandlung eines Objekts in ein Array stoßen ...

E-Commerce-Plattform SKU und SPU-Datenbankdesign: Wie berücksichtigen Sie sowohl benutzerdefinierte Attribute als auch Attributloses Produkte? E-Commerce-Plattform SKU und SPU-Datenbankdesign: Wie berücksichtigen Sie sowohl benutzerdefinierte Attribute als auch Attributloses Produkte? Apr 19, 2025 pm 11:27 PM

Detaillierte Erläuterung des Designs von SKU- und SPU-Tabellen auf E-Commerce-Plattformen In diesem Artikel werden die Datenbankdesignprobleme von SKU und SPU in E-Commerce-Plattformen erörtert, insbesondere wie man mit benutzerdefinierten Verkäufen umgeht ...

Wie kann ich elegant den variablen Entitätsklassennamen erstellen, wenn Tkmybatis für Datenbankabfrage verwendet werden? Wie kann ich elegant den variablen Entitätsklassennamen erstellen, wenn Tkmybatis für Datenbankabfrage verwendet werden? Apr 19, 2025 pm 09:51 PM

Wenn Sie TKMybatis für Datenbankabfragen verwenden, ist das Aufbau von Abfragebedingungen ein häufiges Problem. Dieser Artikel wird ...

See all articles