[JAVA] L'histoire de l'introduction de Gradle en tant que modernisation d'un système existant qui ne gérait pas de packages

À propos de ce matériel

<! - TODO: Faites attention si les différents liens et notations sont pour 2018. Faites particulièrement attention au lien Twitter! !! -> Le matériel de présentation pour la session de titre du JJUG CCC 2019 Spring a été publié sur Qiita (twitter: # ccc_a2 //twitter.com/search? q =% 23ccc_a2)).

<! - Remplacez par l'image des enceintes de la platine des enceintes-> <! - TODO: Correction de la destination du lien! !! -> image.png

Le contenu est presque le même que celui de la diapositive ci-dessus, veuillez donc le voir de manière facile à lire.

introduction

Maven, Gradle, etc., qui sont désormais monnaie courante ...

<! - TODO: Gardez le dos de la série chronologique->

Notre société M3 Co., Ltd. a été fondée en 2000 («J2SE», à l'époque de Java 2). J'utilise Java depuis l'époque où Maven, Gradle et Ivy n'étaient pas encore là.

Le résultat de la pleine utilisation de Java en l'absence de Maven et Gradle ...

Lorsque vous faites git clone, le fichier suivant sera ...

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
                 ...Continue sans fin...

En raison du nombre croissant de bibliothèques utilisées au cours de l'histoire, 182 .jars roulaient.

Opérations qui gèrent directement .jar

J'étais en état de maintenance avec un tel processus:

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

La douleur de la mise à niveau de la bibliothèque

Exemple: je veux mettre à jour la version de ʻaws-java-sdk` pour utiliser de nouvelles fonctionnalités

Le système aws-java-sdk dépend indirectement de plusieurs bibliothèques

Je ne sais pas comment mettre à jour 182 .jars

Abandonnez l'utilisation des nouvelles fonctionnalités AWS: pleurez:

Dépendance indirecte

Je n'utilise pas de pot, je veux donc le supprimer

Peut-être que l'un des pots en dépend ...

Le bocal inutile ne peut pas être nettoyé

Pour empêcher les mises à niveau de la version JVM et les contre-mesures de vulnérabilité: pleurez:

Je ne peux pas utiliser divers outils

Je veux vérifier les informations de vulnérabilité

Vérifiez périodiquement 182 .jars par rapport aux informations de vulnérabilité

Dur et limité

J'ai tendance à le laisser tranquille

Gradle, maven, etc. peuvent être automatisés avec le plugin OWASP dependency-check ...

Le fond qui était devenu comme ça

En dehors de ce système, maven et Gradle ont déjà été installés, mais ...

  • Le système existe depuis sa création et a une histoire particulièrement longue.
  • Le script de construction d'Ant est étroitement assemblé et le remplacement par lots est difficile ―― Puisque le travail de développement habituel se déroule sans problèmes ... (* Tant que l'obscurité autour de la bibliothèque est ignorée) </ small>

Dans ces circonstances, il peut y avoir des cas dans le monde où les outils de gestion de paquets ne sont pas inclus.

Incluez des outils de gestion de paquets (Gradle, maven, etc.)!

Mais comment l'implémenter dans un projet existant ...?

―― Que faire des points qui ont tendance à augmenter la charge de travail? ―― Quels sont les effets secondaires et les effets de son ajout?

→ Aller au chapitre suivant

<! - ===================================== # Section: Partie stratégique (Gradle) == =================================== ->

Stratégie de mise en œuvre de l'outil de gestion des packages

~ Amélioration historique du système __Définition de __scope possible ~

Les défis de la mise en œuvre des outils de gestion des packages

La modernisation des systèmes existants présente un certain nombre de défis:

―― Est-il bon que le pot change avant et après l'introduction de l'outil?

  • Que faire des bocaux difficiles à réobtenir ou qui ne correspondent pas au fichier central?
  • Souhaitez-vous modifier le processus de construction?

Il vaut mieux avoir une politique pour ne pas être influencé par les problèmes.

Politique définie dans notre cas

  • Ne faites pas de différence dans le fichier .jar avant et après l'introduction de l'outil de gestion de paquets.
  • Réduire les inquiétudes concernant l'impact sur l'application et le fardeau des tests
  • Assurez-vous que la seule différence inévitable est une différence inoffensive (la méthode sera décrite plus tard) </ small>
  • L'inventaire et la vérification sont la portée de la prochaine amélioration
  • Ne touchez pas au processus de construction
  • Tout d'abord, améliorez la gestion des paquets!

Axé sur les avantages des outils de gestion des packages Créé une situation où vous pouvez relever de petits défis significatifs.

État avant l'introduction de l'outil de gestion des packages

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

Cela s'est produit avec l'introduction de l'outil de gestion des packages

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

Avantages et inconvénients d'élever .jar vers Git

: + 1: Avantages:

--Facile à migrer depuis Ant, etc.

  • Utilisez toujours le même fichier jar

: -1: Inconvénients:

  • Il ne reste plus --Si vous avez vraiment un problème avec Ant, remplacez-le à ce moment-là
  • Les mises à jour répétées de .jar feront croître le référentiel
  • Parfois, il sera séparé en tant que sous-module Git

Stratégie d'amélioration héritée

Identifier le vrai «problème» et le «mérite de changer»

Considérez la "portée minimale nécessaire et suffisante" pour cela.

Atteindre l'objectif avec un petit défi (performances élevées, petits dommages même si vous échouez) </ petit>

Au lieu de "Parce que c'est un héritage, il faut tout tuer !!!" Des améliorations tout en suivant les bons points existants et les points qui n'ont pas besoin d'être modifiés.

Partie technique (tactique)

Technique de déploiement de l'outil de gestion des packages: comment moderniser Gradle

~ Mesures spécifiques pour faire face à divers problèmes qui ont tendance à être modernisés ~

Gradle or Maven

Gradle est recommandé pour des applications comme celle-ci:

--Flexibilité: le traitement flexible peut être décrit avec Groovy et Kotlin DSL --Maven peut ne pas être en mesure de gérer la structure des projets historiques --Investigative: Groovy Javadoc est plus facile à lire (subjectif) </ small> --Productivité: profitez pleinement du débogueur de l'EDI

  • Tu n'as pas à te battre comme une boîte noire --Reproductibilité: le wrapper Gradle facilite (relativement) la reproductibilité du comportement

* En général, Maven est meilleur que les autres. </ Small>

Copie de fichier par Gradle

Pour introduire Gradle tout en utilisant le système de construction existant Je souhaite copier les fichiers suivants dans le répertoire spécifié avec Gradle:

--Jar qui dépend du temps de compilation et du temps d'exécution

  • Jar qui dépend du test unitaire
  • Source jar

Je souhaite également maintenir automatiquement le fichier .classpath (décrit plus loin) </ small>.

Téléchargez le fichier jar avec Gradle

Étonnamment facile:

def compileJarCopyTo = 'development/lib/app'

task downloadJars() {
  doLast {
    //À la destination de la copie*.Effacez le pot
    delete fileTree(dir: compileJarCopyTo, include: '*.jar')

    //faire une copie
    copy {
      from configurations.compile
      into compileJarCopyTo
    }
  }
}

copy task

Pratique pour spécifier le fichier jar à copier et inclure, exclure, etc.:

copy {
  // testCompile =Copiez les jars dépendants avec test
  from configurations.testCompile

  into testCompileJarCopyTo

  //Ignorer les jars qui correspondent au modèle spécifié
  exclude 'jmockit-*.jar'
}

Vous pouvez également copier le fichier jar source

Pour copier le fichier jar source, écrivez du code pour manipuler ces lunettes:

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` est également apparu ...) </ small>

→ Reportez-vous au code de Gradle 2.x du prédécesseur, et reportez-vous à la version compatible Gradle 5.x
Copier les fichiers jar source dans le répertoire (Qiita ) Publié dans

Générer un fichier .classpath

Un fichier de configuration qui permet à l'EDI de charger les fichiers JAR et le code source. Initialement pour Eclipse, il prend également en charge InteliJ IDEA.

Je souhaite également maintenir ce fichier avec Gradle.

Il peut être généré simplement en appliquant le plugin ʻeclipse` de Gradle ...

.classpath Problème de chemin absolu

Le chemin dans .classpath généré par Plugin est un chemin absolu. C'est peu pratique car il devient un chemin dépendant de l'environnement et ne peut pas être partagé sur Git.

Solution: --Générer .classpath à chaque fois par gradle eclipseClasspath de vos propres mains -: -1: Il faut du temps à tout le monde pour le faire à chaque fois -: -1: La reproductibilité de la construction diminue (même si cela a fonctionné à portée de main! Phénomène) --Générer .classpath en notation de chemin relatif avec Gradle et valider avec le fichier jar -: + 1: Exécutez-le simplement avec une copie du fichier Jar etc. OK

Générer .classpath en notation de chemin relatif

Si vous l'étendez en utilisant le hook du plugin comme indiqué dans Site de référence au lieu de pathVariables '.': ProjectDir du plugin ʻeclipse` bien:

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

ʻEclipse.classpath.file`` quandMergé`

Vous pouvez contrôler librement le contenu du fichier .classpath avec whenMerged

Par exemple:

  • Réécrivez le chemin de référence du fichier jar avec une logique arbitraire
  • Dans notre cas, seuls certains fichiers sont placés dans des répertoires différents. -- classpath.entries.sort contrôle l'ordre de .classpath
  • Utile pour les mesures de bibliothèque dépendant de l'ordre de chargement telles que JMockit --classpath.getEntries (). removeAll {return (expression conditionnelle)}
  • Vous pouvez exclure les fichiers JAR que vous ne voulez pas que l'EDI charge

Changement de nom de fichier jar

Les noms de fichiers JAR de gestion manuelle et les fichiers JAR dérivés de Gradle ne correspondent souvent pas. Par exemple:

--Nom de fichier géré manuellement: crimson.jar

  • Résultat du téléchargement de la plate-forme: crimson-1.1.3.jar

Il y a un problème lors du référencement avec un nom de fichier fixe. En particulier, il y a les suivants:

--Fixed file name in classpath of build tools such as Ant

  • Nom de fichier corrigé avec l'option classpath de JVM au démarrage du programme

Solution de contournement pour le changement de nom de fichier JAR

  1. (Non recommandé) Renommez l'ancien nom de fichier en post-traitement -: -1: accident lorsque le nom du groupe source ou de l'artefact change -: -1: j'ai du mal à gérer les nouveaux pots
  2. Ne connaissez pas les bibliothèques individuelles -: + 1: Design OK juste en lisant tous les jars dans un répertoire spécifique --Ant, JVM classpath (> = 6), utilisez des caractères génériques * tels que shell
  • Notez que l'interprétation de «*» est légèrement différente.

Ce dernier est un problème, mais il s'agit d'un effort temporaire, il vaut donc mieux y faire face à long terme.

<! - ===================================== # Section: Partie stratégique (Gestion des pots) = ==================================== ->

Technique d'implémentation de l'outil de gestion de packages: gestion des fichiers JAR pour diverses raisons

~ Techniques de gestion des fichiers jar provenant d'au-delà de l'histoire ~

Éléments communs dans les anciens fichiers JAR

<! ---- Le pot contenu dans le pot tout-en-un est couvert->

  • J'ai pu récupérer le fichier jar, mais les binaires ne correspondent pas
  • VersionSNAPSHOT --Bien que ce ne soit pas -SNAPSHOT`, il a été remplacé et publié. --Il existe différents binaires entre les référentiels Maven
  • Patch d'origine de fond inconnu: imp:
  • La page officielle a disparu et vous ne pouvez pas réobtenir des pots ou des sources

Déterminer la cause de la discordance binaire jar

Ne laissez pas l'écart, vérifiez les différences spécifiques:

  • La portée et le risque de l'introduction d'outils de gestion de paquets peuvent être limités.
  • La plage à tester et la méthode d'essai seront clarifiées.

J'ai émis un hachage SHA-1 du fichier jar avant et après la graduation, Nous avons examiné les différences spécifiques pour les jars avec des hachages incompatibles.

Comment vérifier la différence du fichier jar

Le fichier jar est un zip et une fois décompressé, vous verrez les fichiers suivants:

  1. Fichier .class (code octet Java)
  2. Fichier de métadonnées tel que «META-INF»
  3. Autres fichiers de ressources tels que les fichiers de propriétés

À l'exception de «.class», la plupart des outils de comparaison de texte peuvent être utilisés à des fins de comparaison.

Exemple quand il y a une différence dans META-INF / MANIFEST.MF de lucene-analyzers-2.4.0: </ 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

Comment vérifier les différences de jar: fichier de classe

Le fichier .class est un binaire de code d'octet Java.

En convertissant en une représentation textuelle avec javap -c inclus dans le JDK Il devient possible de comparer avec l'outil de comparaison de texte.

Exemple quand il y a une différence dans guice-servlet-1.0.jar:

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 {

(remplacé par jar avec final ajouté) </ small>

Bibliothèque non récupérable

Mesures autres que la suspension de l'utilisation de la bibliothèque:

  • (: imp: obsolète) Télécharger vers un référentiel public tel que Central -: -1: Licence et moralement défavorable -: -1: pour publier un fichier jar non confirmé qui correspond à un fichier jar connu
  • (: Thinking: Subtle) Utilisez directement le fichier .java de la bibliothèque cible -: -1: Puisque la source est utilisée directement, les modifications d'origine et le couplage serré ont tendance à se produire. -: -1: Il y a un problème selon la licence
  • (Recommandé) Géré par un référentiel interne privé -: + 1: les problèmes de droits sont moins susceptibles de se produire -: + 1: Facile à saisir et supprimer l'état d'utilisation de la bibliothèque

Dépôt privé

Non limité aux jars non récupérables, mais aussi à la gestion de bibliothèques internes, etc. Il est pratique d'avoir un référentiel privé.

Méthode de construction commune:

  1. Parcourez le référentiel maven local avec file: //
  • Nécessite une synchronisation entre les machines
  • A tendance à compromettre la reproductibilité de la construction
  • Il y a aussi le risque de perdre le pot et la difficulté de la sauvegarde.
  1. Exécutez un serveur de référentiel tel que Nexus ou Artifactory (pratique)
  • Je n'entrerai pas dans la méthode de configuration détaillée, mais Nexus est plus facile pour les nouvelles configurations.

Utilisation du référentiel privé

  1. Obtenez les bibliothèques qui existent dans le monde à partir de maven central etc. comme auparavant
  2. Obtenez des choses privées de votre référentiel privé

Avec Gradle, vous pouvez le faire simplement en:

repositories {
  maven {
    url 'http://central.maven.org/maven2/'    
  } // mavenCentral()Je n'ose pas utiliser la notation abrégée(Voir ci-dessous)

  maven {
    url "http://URL du référentiel privé"
  }
}

Télécharger le fichier jar dans le référentiel

<! - TODO: Cette description peut ne pas être nécessaire selon les hypothèses au niveau du lecteur ... Mais devrais-je écrire quelque chose pour les gens qui sont Gradle et ne connaissent pas maven? ->

Écrivez les métadonnées au format XML de Maven (pom.xml) et téléchargez-les avec le fichier jar.

Cela peut sembler gênant à première vue, mais c'est facile si vous vous concentrez sur cet objectif:

<project>
  <modelVersion>4.0.0</modelVersion>

  <!--Informations d'identification de ce pot lui-même-->
  <groupId>com.m3</groupId> <artifactId>m3generator</artifactId>
  <version>1.0.0</version>

  <!--Informations sur le pot dont dépend ce pot-->
  <dependencies>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    ...

(Artifactory) </ small> Méfiez-vous des POM générés automatiquement

Cela semble pratique car Artifactory génère automatiquement un POM ...

«» est souvent vide ou incorrect

Je ne peux pas obtenir d'informations sur les bibliothèques dépendantes du fichier jar téléchargé

Les avantages de la gestion des dépendances avec les outils de gestion des packages sont perdus

Écrivons correctement <dependencies> sans le lancer en génération automatique.

Chevauchement de bibliothèques entre référentiels

S'il y a des bibliothèques avec le même nom mais qui ne correspondent pas (avec des différences) Vous devez contrôler explicitement lequel est chargé:

  • Télécharger dans un référentiel privé comme une autre version --Ou, contrôle du côté Gradle (ci-dessous)
repositories {
  maven { // Maven central
    url 'http://central.maven.org/maven2/'    

    content {
      excludeGroup 'com.sun.jmx' //Ne récupérez pas ce groupe d'ici
      excludeModule 'jdom', 'jdom' //Ne récupérez pas cette bibliothèque d'ici
    }
    //MavenCentral pour faire la description ci-dessus()Je n'utilise pas la notation abrégée telle que
  }

finalement

Next Step

Ce que vous souhaitez en particulier faire si vous incluez un outil de gestion de packages:

  • Détection de collision de version --Détection des doublons sur le chemin de classe
  • Vérification des informations de vulnérabilité par contrôle de dépendance OWASP

Une explication plus approfondie sur les diapositives du printemps JJUG 2018:

--Title: Comment faire un compromis entre Spring Boot et les bibliothèques générales

  • La seconde moitié du matériel est des informations qui peuvent être utilisées indépendamment du Spring Framework

Résumé

Cette fois, le processus lors de l'installation de l'outil de gestion des packages:

--Définir des objectifs ――Dessinez une vision de l'amélioration de la gestion des paquets --Construire une stratégie ―― Que faire pour la réalisation ・ Qu'est-ce que vous n'osez pas faire? --Résolution des problèmes avec les techniques: diverses idées évoquées cette fois --Utilisation de Gradle

  • Vérification de la différence de pot --Utilisation d'un référentiel privé

Même dans une situation où vous pouvez penser que l'obscurité est si profonde que vous ne pouvez pas la toucher __ Définissez la portée appropriée et réalisez avec la technologie __ pour aller de l'avant.

Recommended Posts