[JAVA] Die Geschichte der Einführung von Gradle als Nachrüstung eines bestehenden Systems, das keine Pakete verwaltet

Über dieses Material

<! - TODO: Seien Sie vorsichtig, wenn die verschiedenen Links und Notationen für 2018 sind. Achten Sie besonders auf den Twitter-Link! !! -> Das Präsentationsmaterial für die Titelsitzung von JJUG CCC 2019 Spring wurde auf Qiita (Twitter: # ccc_a2 veröffentlicht. //twitter.com/search? q =% 23ccc_a2)).

<! - Ersetzen Sie durch das Lautsprecherbild von Speakers deck-> <! - TODO: Linkziel muss korrigiert werden! !! -> image.png

Der Inhalt ist fast der gleiche wie auf der obigen Folie. Bitte sehen Sie ihn leicht lesbar.

Einführung

Maven, Gradle usw., die heute alltäglich sind ...

<! - TODO: Behalte den Rücken der Zeitreihe->

Unsere Firma M3 Co., Ltd. wurde im Jahr 2000 gegründet (J2SE, die Ära um Java 2). Ich benutze Java seit den Tagen, als Maven, Gradle und Ivy noch nicht da waren.

Das Ergebnis der vollständigen Nutzung von Java in Abwesenheit von Maven und Gradle ...

Wenn Sie "Git Clone" ausführen, lautet die folgende Datei ...

lib/app/hibernate-validator-4.3.0.Final.jar
lib/app/aws-java-sdk-core-1.10.27.jar
lib/app/aws-java-sdk-s3-1.10.27.jar
lib/app/generator-runtime-0.3.0-20050901.1909.jar
lib/app/xalan.jar
lib/app/crimson.jar
                 ...Geht endlos weiter...

Infolge der zunehmenden Anzahl von Bibliotheken, die im Laufe der Geschichte verwendet wurden, rollten 182 ".jar".

Operationen, die .jar direkt verwalten

Ich war mit einem solchen Prozess in einem Wartungszustand:

適当なところから手作業で jar をダウンロードして Git に入れるという闇のオペレーションの図

Der Schmerz, die Bibliothek zu aktualisieren

Beispiel: Ich möchte die Version von aws-java-sdk aktualisieren, um die neuen Funktionen nutzen zu können

Das aws-java-sdk-System hängt indirekt von mehreren Bibliotheken ab

Ich weiß nicht, wie ich 182 .jars aktualisieren soll

Geben Sie die Verwendung neuer AWS-Funktionen auf: cry:

Indirekte Abhängigkeit

Ich benutze kein Glas, also möchte ich es löschen

Vielleicht hängt eines der Gläser davon ab ...

Unnötiges Glas kann nicht gereinigt werden

Um JVM-Versions-Upgrades und Gegenmaßnahmen gegen Sicherheitslücken zu verhindern: cry:

Ich kann keine verschiedenen Werkzeuge verwenden

Ich möchte Informationen zu Sicherheitslücken überprüfen

Überprüfen Sie 182 .jars regelmäßig auf Informationen zu Sicherheitslücken

Robust und begrenzt

Ich neige dazu, es in Ruhe zu lassen

Gradle, Maven usw. können mit dem OWASP-Plugin "Dependency-Check" automatisiert werden ...

Der Hintergrund, der so geworden war

Abgesehen von diesem System wurden Maven und Gradle bereits installiert, aber ...

Unter diesen Umständen kann es weltweit Fälle geben, in denen Paketverwaltungstools nicht enthalten sind.

Fügen Sie Paketverwaltungstools (Gradle, Maven usw.) hinzu!

Aber wie implementiert man es in ein bestehendes Projekt ...?

――Was tun mit den Punkten, die die Arbeitsbelastung erhöhen? ――Was sind die Nebenwirkungen und Auswirkungen des Hinzufügens?

→ Fahren Sie mit dem nächsten Kapitel fort

<! - =================================== # Abschnitt: Strategischer Teil (Gradle) == ================================= ->

Implementierungsstrategie für das Paketverwaltungstool

~ Historische Systemverbesserung __Mögliche __Bereichsdefinition ~

Herausforderungen bei der Implementierung von Paketverwaltungstools

Die Nachrüstung bestehender Systeme birgt eine Reihe von Herausforderungen:

――Ist es gut, dass sich das Glas vor und nach der Einführung des Tools ändert? --Was tun mit schwer zu beschaffenden Gläsern oder Gläsern, die nicht zur Mitte passen?

Es ist besser, eine Richtlinie zu haben, damit Sie nicht von Problemen beeinflusst werden.

In unserem Fall festgelegte Richtlinien

Konzentriert sich darauf, von Paketverwaltungstools zu profitieren Es wurde eine Situation geschaffen, in der Sie sich kleinen und bedeutungsvollen Herausforderungen stellen können.

Geben Sie vor der Einführung des Paketverwaltungstools an

適当なところから手作業で jar をダウンロードして Git に入れるという闇のオペレーションの図

Dies geschah mit der Einführung des Paketverwaltungstools

jar のダウンロードだけを Gradle 化した図

Vor- und Nachteile der Erhöhung von .jar auf Git

: + 1: Vorteile:

: -1: Nachteile:

--Ant bleibt

Legacy-Verbesserungsstrategie

Identifizieren Sie die wahren "Probleme" und "Verdienste um Änderungen"

Betrachten Sie den "notwendigen und ausreichenden Mindestumfang" dafür.

Erreichen Sie das Ziel mit "kleiner Herausforderung" (hohe Kostenleistung, geringer Schaden, selbst wenn Sie versagen) </ klein>

Anstelle von "Weil es ein Vermächtnis ist, musst du alles töten !!!" Verbesserungen beim Befolgen der vorhandenen guten Punkte und Punkte, die nicht geändert werden müssen.

Technik (Taktik) Teil

Bereitstellungstechnik für das Paketverwaltungstool: Nachrüsten von Gradle

~ Spezifische Maßnahmen zur Bewältigung verschiedener Probleme, die tendenziell nachgerüstet werden ~

Gradle or Maven

Gradle wird für Anwendungen wie diese empfohlen:

* Im Allgemeinen ist Maven besser als andere. </ Small>

Dateikopie von Gradle

Einführung von Gradle unter Verwendung des vorhandenen Build-Systems Ich möchte die folgenden Dateien mit Gradle in das angegebene Verzeichnis kopieren:

--Jar, das von der Kompilierungszeit und der Laufzeit abhängt

Ich möchte auch automatisch die .classpath-Datei (später beschrieben) </ small> pflegen.

Laden Sie die JAR-Datei mit Gradle herunter

Überraschend einfach:

def compileJarCopyTo = 'development/lib/app'

task downloadJars() {
  doLast {
    //Am Kopierziel*.Löschen Sie das Glas
    delete fileTree(dir: compileJarCopyTo, include: '*.jar')

    //eine Kopie machen
    copy {
      from configurations.compile
      into compileJarCopyTo
    }
  }
}

copy task

Praktisch, um das zu kopierende Glas anzugeben und einzuschließen, auszuschließen usw.:

copy {
  // testCompile =Kopieren Sie die abhängigen Gläser mit Test
  from configurations.testCompile

  into testCompileJarCopyTo

  //Ignorieren Sie Gläser, die dem angegebenen Muster entsprechen
  exclude 'jmockit-*.jar'
}

Sie können auch das Quellglas kopieren

Um das Quellglas zu kopieren, schreiben Sie Code, um diese Schutzbrillen zu manipulieren:

import org.gradle.jvm.JvmLibrary
import org.gradle.language.base.artifact.SourcesArtifact
import org.gradle.api.artifacts.query.ArtifactResolutionQuery
import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier

(org.gradle.internal ist ebenfalls erschienen ...) </ small>

→ Lesen Sie den Code für Gradle 2.x des Vorgängers und die Gradle 5.x-kompatible Version
Quell-JAR-Dateien in Verzeichnis kopieren (Qiita) ) Veröffentlicht in

Generieren Sie eine .classpath-Datei

Eine Konfigurationsdatei, mit der die IDE Jars und Quellcode laden kann. Ursprünglich für Eclipse, unterstützt es auch InteliJ IDEA.

Ich möchte diese Datei auch mit Gradle pflegen.

Es kann einfach durch Anwenden von Gradles "Eclipse" -Plugin generiert werden ...

.classpath Absolutes Pfadproblem

Der vom Plugin generierte Pfad in .classpath ist ein absoluter Pfad. Dies ist unpraktisch, da es sich um einen umgebungsabhängigen Pfad handelt und nicht auf Git freigegeben werden kann.

Lösung:

  • Generieren Sie ".classpath" jedes Mal mit "gradle eclipseClasspath" in Ihren eigenen Händen -: -1: Es braucht Zeit, bis jeder es jedes Mal tut -: -1: Die Reproduzierbarkeit des Builds nimmt ab (obwohl es sofort funktioniert hat! Phänomen)
  • Generieren Sie ".classpath" in relativer Pfadnotation mit Gradle und schreiben Sie es mit der JAR-Datei fest -: + 1: Führen Sie es einfach zusammen mit einer Kopie der Jar-Datei usw. aus. OK

Generieren Sie ".classpath" in relativer Pfadnotation

Wenn Sie es mit dem Hook des Plugins erweitern, wie in Referenzseite anstelle von "pathVariables" gezeigt. ": ProjectDir" des "Eclipse" -Plugins gut:

eclipse.classpath.file {
    whenMerged { classpath ->
        classpath.entries.findAll { entry -> entry.kind == 'lib' }.each {
            it.path = it.path.replaceFirst("${projectDir.absolutePath}/", '')
            it.exported = false
        }
    }
}

WhenMerged in eclipse.classpath.file

Sie können den Inhalt der .classpath-Datei mit whenMerged frei steuern

Zum Beispiel:

  • Schreiben Sie den Referenzpfad der JAR-Datei mit beliebiger Logik neu
  • In unserem Fall werden nur einige Dateien in verschiedenen Verzeichnissen abgelegt. -- classpath.entries.sort steuert die Reihenfolge von .classpath
  • Nützlich für ladeauftragsabhängige Bibliotheksmaßnahmen wie JMockit --classpath.getEntries (). removeAll {return (bedingter Ausdruck)}
  • Sie können Gläser ausschließen, die die IDE nicht laden soll

Änderung des JAR-Dateinamens

Manuelle Verwaltungsglas-Dateinamen und von Gradle abgeleitete Gläser stimmen häufig nicht überein. Zum Beispiel:

  • Manuell verwalteter Dateiname: crimson.jar --Gradle Download Ergebnis: crimson-1.1.3.jar

Beim Verweisen mit einem festen Dateinamen tritt ein Problem auf. Insbesondere gibt es Folgendes:

  • Der feste Dateiname im Klassenpfad von Build-Tools wie Ant
  • Der Dateiname wurde beim Programmstart mit der Option "Klassenpfad" der JVM festgelegt

Problemumgehung für die Änderung des JAR-Dateinamens

  1. (Nicht empfohlen) In der Nachbearbeitung in den alten Dateinamen umbenennen -: -1: Unfall, wenn sich der Name der Quellgruppe oder des Artefakts umbenennt -: -1: Ich habe Probleme mit neuen Gläsern
  2. Achten Sie nicht auf einzelne Bibliotheken -: + 1: Entwerfen Sie OK, indem Sie alle Gläser in einem bestimmten Verzeichnis lesen --Ant, JVM classpath (> = 6), benutze * Platzhalter wie Shell
  • Beachten Sie, dass die Interpretation von * etwas anders ist.

Letzteres ist ein Ärger, aber es ist eine vorübergehende Anstrengung, daher ist es besser, langfristig damit umzugehen.

<! - =================================== # Abschnitt: Strategischer Teil (Jar Management) = =================================== ->

Implementierungstechnik für das Paketverwaltungstool: Verwalten von Gläsern aus verschiedenen Gründen

~ Techniken für den Umgang mit JAR-Dateien, die aus der Vergangenheit stammen ~

Häufige Dinge in alten JAR-Dateien

<! ---- Das im All-in-One-Glas enthaltene Glas ist abgedeckt->

  • Ich konnte das Glas wieder erhalten, aber die Binärdateien stimmen nicht überein --SNAPSHOT Version
  • Obwohl es kein "SNAPSHOT" ist, wurde es ersetzt und veröffentlicht.
  • Es gibt verschiedene Binärdateien zwischen Maven-Repositorys
  • Ursprünglicher Fleck mit unbekanntem Hintergrund: imp:
  • Die offizielle Seite ist verschwunden und Sie können keine Gläser oder Quellen mehr erhalten

Bestimmen Sie die Ursache für die binäre Nichtübereinstimmung des JAR

Lassen Sie die Diskrepanz nicht, sondern überprüfen Sie nur die spezifischen Unterschiede:

  • Der Umfang und das Risiko der Einführung von Paketverwaltungstools können begrenzt sein.
  • Der zu testende Bereich und die Testmethode werden geklärt.

Ich habe vor und nach der Gradleisierung einen SHA-1-Hash der JAR-Datei ausgegeben. Wir haben uns die spezifischen Unterschiede für Gläser mit nicht übereinstimmenden Hashes angesehen.

So überprüfen Sie den Unterschied zwischen JAR-Dateien

Die JAR-Datei ist eine Zip-Datei. Nach dem Entpacken werden die folgenden Dateien angezeigt:

  1. .class Datei (Java Byte Code)
  2. Metadatendatei wie "META-INF"
  3. Andere Ressourcendateien, z. B. Eigenschaftendateien

Mit Ausnahme von ".class" können die meisten Textvergleichstools zum Vergleich verwendet werden.

Beispiel, wenn es einen Unterschied in "META-INF / MANIFEST.MF" von "Lucene-Analysatoren-2.4.0" gibt: </ small>

8c8
< Implementation-Version: 2.4.0 701827 - 2008-10-05 16:46:27
> Implementation-Version: 2.4.0 701827 - 2008-10-05 16:44:47

So überprüfen Sie JAR-Unterschiede: Klassendatei

Die .class-Datei ist eine Java-Bytecode-Binärdatei.

Durch Konvertieren in eine Textdarstellung mit "javap -c" im JDK Es wird möglich, mit dem Textvergleichstool zu vergleichen.

Beispiel, wenn es einen Unterschied in guice-servlet-1.0.jar gibt:

2c2
< final class com.google.inject.servlet.ServletScopes$1 implements com.google.inject.Scope {
> class com.google.inject.servlet.ServletScopes$1 implements com.google.inject.Scope {

(ersetzt durch jar mit final hinzugefügt) </ small>

Nicht abrufbare Bibliothek

Andere Maßnahmen als die Aussetzung der Nutzung der Bibliothek:

  • (: imp: Veraltet) In ein öffentliches Repository wie Central hochladen -: -1: Lizenz und moralisch ungünstig -: -1: Zum Veröffentlichen eines unbestätigten Glases, das einem bekannten Glas entspricht
  • (: Thinking: Subtle) Verwenden Sie die .java-Datei der Zielbibliothek direkt -: -1: Da die Quelle direkt verwendet wird, treten in der Regel Originalmodifikationen und eine enge Kopplung auf. -: -1: Abhängig von der Lizenz liegt ein Problem vor
  • (Empfohlen) Wird vom privaten internen Repository verwaltet -: + 1: Rechteprobleme treten seltener auf -: + 1: Einfach zu erfassen und den Nutzungsstatus der Bibliothek zu löschen

Privater Bereich

Nicht nur für nicht abrufbare Gläser, sondern auch für die Verwaltung interner Bibliotheken usw. Es ist praktisch, ein privates Repository zu haben.

Übliche Bauweise:

  1. Durchsuchen Sie das lokale Maven-Repository mit file: //
  • Benötigt Synchronisation zwischen Maschinen
  • Neigt dazu, die Reproduzierbarkeit des Builds zu beeinträchtigen
  • Es besteht auch die Gefahr, dass das Glas verloren geht und Probleme beim Sichern auftreten.
  1. Führen Sie einen Repository-Server wie Nexus oder Artifactory (bequem) aus.
  • Ich werde nicht auf die detaillierte Setup-Methode eingehen, aber Nexus ist für neue Setups einfacher.

Verwendung des privaten Repositorys

  1. Beziehen Sie die Bibliotheken, die auf der Welt existieren, wie zuvor von Maven Central usw.
  2. Holen Sie sich private Dinge aus Ihrem privaten Repository

Mit Gradle können Sie dies einfach tun, indem Sie:

repositories {
  maven {
    url 'http://central.maven.org/maven2/'    
  } // mavenCentral()Ich wage es nicht, die Kurznotation zu verwenden(Siehe unten)

  maven {
    url "http://URL des privaten Repositorys"
  }
}

Laden Sie das Glas in das Repository hoch

<! - TODO: Diese Beschreibung ist abhängig von den Annahmen auf Leserebene möglicherweise nicht erforderlich ... Aber sollte ich so etwas wie Gradle für Leute schreiben, die Maven nicht kennen? ->

Schreiben Sie die Metadaten im XML-Format (pom.xml) von Maven und laden Sie sie mit dem jar hoch.

Auf den ersten Blick mag es unangenehm erscheinen, aber es ist einfach, wenn Sie sich auf diesen Zweck konzentrieren:

<project>
  <modelVersion>4.0.0</modelVersion>

  <!--Identifikationsinformationen dieses Glases selbst-->
  <groupId>com.m3</groupId> <artifactId>m3generator</artifactId>
  <version>1.0.0</version>

  <!--Informationen zu dem Glas, von dem dieses Glas abhängt-->
  <dependencies>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    ...

(Artifactory) </ small> Vorsicht vor automatisch generiertem POM

Es sieht praktisch aus, da Artifactory automatisch ein POM generiert ...

<Abhängigkeiten> ist oft leer oder falsch

Ich kann keine Informationen über die abhängigen Bibliotheken des hochgeladenen JARs erhalten

Die Vorteile des Abhängigkeitsmanagements mit Paketverwaltungstools gehen verloren

Lassen Sie uns "<Abhängigkeiten>" richtig schreiben, ohne es auf die automatische Generierung zu werfen.

Überlappende Bibliotheken zwischen Repositorys

Wenn es Bibliotheken mit demselben Namen gibt, die jedoch nicht übereinstimmen (mit Unterschieden) Sie sollten explizit steuern, welches geladen wird:

  • In eine andere Version in das private Repository hochladen
  • Oder Kontrolle auf der Gradle-Seite (unten)
repositories {
  maven { // Maven central
    url 'http://central.maven.org/maven2/'    

    content {
      excludeGroup 'com.sun.jmx' //Bekomme diese Gruppe nicht von hier
      excludeModule 'jdom', 'jdom' //Erhalten Sie diese Bibliothek nicht von hier
    }
    //MavenCentral, um die obige Beschreibung vorzunehmen()Ich verwende nicht die abgekürzte Notation wie
  }

Schließlich

Next Step

Was Sie besonders tun möchten, wenn Sie ein Paketverwaltungstool hinzufügen:

--Versionskollisionserkennung

  • Doppelte Erkennung im Klassenpfad --Überprüfen von Schwachstelleninformationen durch OWASP-Abhängigkeitsprüfung

Eine ausführlichere Erklärung zu den JJUG 2018 Spring-Folien:

--Titel: Wie man einen Kompromiss zwischen Spring Boot und allgemeinen Bibliotheken eingeht

  • Die zweite Hälfte des Materials besteht aus Informationen, die unabhängig vom Spring Framework verwendet werden können.

Zusammenfassung

Diesmal der Prozess, bei dem das Paketverwaltungstool installiert wurde:

  • Ziele definieren ――Erstellen Sie eine Vision, wie sich das Paketmanagement verbessern wird --Erstellen Sie eine Strategie ――Was tun zur Realisierung? ・ Was wagen Sie nicht zu tun?
  • Probleme mit Techniken lösen: Diesmal wurden verschiedene Ideen erwähnt
  • Nutzung von Gradle --Jar Differenzprüfung
  • Nutzung des privaten Repositorys

Selbst in einer Situation, in der Sie denken können, dass die Dunkelheit so tief ist, dass Sie sie nicht berühren können __ Stellen Sie den geeigneten Umfang ein und realisieren Sie mit Technologie __, um vorwärts zu kommen.

Recommended Posts