Condividi tramite


Risolvere i conflitti di versione delle dipendenze

Questo articolo descrive i conflitti di versione delle dipendenze e come risolverli.

Azure librerie client per Java dipendono dalle librerie di terze parti più diffuse, ad esempio quelle seguenti:

Molte applicazioni e framework di Java usano direttamente o transitivamente queste librerie, che comportano conflitti di versione. Le gestioni dipendenze, ad esempio Maven e Gradle , risolvono tutte le dipendenze in modo che sia presente una sola versione di ogni dipendenza dal classpath. Tuttavia, non è garantito che la versione della dipendenza risolta sia compatibile con tutti i consumatori di tale dipendenza nell'applicazione. Per altre informazioni, vedere Introduzione al meccanismo di dipendenza nella documentazione di Maven e Informazioni sulla risoluzione delle dipendenze nella documentazione di Gradle.

L'incompatibilità API delle dipendenze dirette genera errori di compilazione. L'incompatibilità delle dipendenze diamond genera in genere errori di runtime, ad esempio NoClassDefFoundError, NoSuchMethodError o un altro LinkageError. Non tutte le librerie seguono rigorosamente il controllo delle versioni semantiche e talvolta le modifiche di rilievo si verificano nella stessa versione principale.

Diagnosticare i problemi di mancata corrispondenza della versione

Le sezioni seguenti descrivono i metodi su come diagnosticare i problemi di mancata corrispondenza della versione.

Usare il Azure SDK per lo strumento di compilazione Java

Il Azure SDK per Java strumento di compilazione, introdotto in Introduzione a Azure SDK e Apache Maven, consente di identificare i problemi comuni riscontrati. È consigliabile aggiungere questo strumento di compilazione al progetto ed eseguirlo aggiungendo la azure:run destinazione Maven al processo di compilazione regolare. Con la configurazione appropriata, è possibile identificare e risolvere i conflitti di dipendenza in modo più proattivo, prima che diventino problemi in fase di esecuzione.

Visualizzare un albero delle dipendenze

Eseguire mvn dependency:tree o gradle dependencies --scan per visualizzare l'albero delle dipendenze completo per l'applicazione, con numeri di versione. mvn dependency:tree -Dverbose fornisce altre informazioni, ma può essere fuorviante. Per altre informazioni, vedere Apache Maven Dependency Tree nella documentazione di Maven. Per ogni libreria sospetta che abbia un conflitto di versione, annotare il numero di versione e determinare quali componenti dipendono da esso.

La risoluzione delle dipendenze negli ambienti di sviluppo e produzione può funzionare in modo diverso. I plug-in Apache Spark, Apache Flink, Databricks e IDE richiedono una configurazione aggiuntiva per le dipendenze personalizzate. Possono anche usare versioni personalizzate di librerie client di Azure o componenti comuni. Per altre informazioni, vedere gli articoli seguenti:

Per altre informazioni sulla risoluzione dei conflitti in tali ambienti, vedere la sezione Creare un file JAR fat più avanti in questo articolo.

Configurare Azure Functions

La versione della dipendenza interna in Azure Functions (in esecuzione solo Java 8) ha la precedenza su una versione fornita dall'utente. Questa dipendenza causa conflitti di versione, in particolare con Jackson, Netty e Reactor.

Per risolvere questo problema, impostare la FUNCTIONS_WORKER_JAVA_LOAD_APP_LIBS variabile di ambiente su true o 1. Assicurarsi di aggiornare gli strumenti per le funzioni Azure (v2 o v3) alla versione più recente.

Annotazioni

Questa configurazione si applica a Azure Functions solo in esecuzione Java 8, le funzioni che eseguono Java 11 non richiedono una configurazione speciale.

Configurare Apache Spark

Il Azure SDK per Java supporta più versioni di Jackson, ma a volte possono verificarsi problemi a seconda degli strumenti di compilazione e dell'ordinamento della risoluzione delle dipendenze. Un buon esempio di questo problema riguarda Apache Spark, versione 3.0.0 e successive, che dipende da Jackson 2.10. Anche se è compatibile con il Azure SDK per Java, gli sviluppatori spesso scopre che viene usata una versione più recente di Jackson, che comporta incompatibilità. Per attenuare questo problema, è necessario aggiungere una versione specifica di Jackson (una compatibile con Spark). Per altre informazioni, vedere la sezione Supporto per più versioni di Jackson in questo articolo.

Se si usano versioni precedenti di Spark o se un'altra libreria usata richiede una versione ancora precedente di Jackson che il Azure SDK per Java non supporta, continuare a leggere questo articolo per i possibili passaggi di mitigazione.

Rilevare la versione del runtime Jackson

In Azure Core 1.21.0 è stato aggiunto il rilevamento del runtime e la diagnostica migliore della versione del runtime Jackson.

Se viene visualizzato LinkageError (o una delle relative sottoclassi) correlate all'API Jackson, controllare il messaggio dell'eccezione per le informazioni sulla versione di runtime. Ad esempio: com.azure.core.implementation.jackson.JacksonVersionMismatchError: com/fasterxml/jackson/databind/cfg/MapperBuilder Package versions: jackson-annotations=2.9.0, jackson-core=2.9.0, jackson-databind=2.9.0, jackson-dataformat-xml=2.9.0, jackson-datatype-jsr310=2.9.0, azure-core=1.19.0-beta.2

Cercare i log degli avvisi e degli errori da JacksonVersion. Per altre informazioni, vedere Configurare la registrazione nel Azure SDK per Java. Ad esempio: [main] ERROR com.azure.core.implementation.jackson.JacksonVersion - Version '2.9.0' of package 'jackson-core' is not supported (too old), please upgrade.

Annotazioni

Verificare che tutti i pacchetti Jackson abbiano la stessa versione.

Per l'elenco dei pacchetti usati da Azure SDK e le versioni di Jackson supportate, vedere la sezione Support for multiple Jackson versions.For the list of packages used by Azure SDK and the supported Jackson versions, see the Support for multiple Jackson versions section.

Attenuare i problemi di mancata corrispondenza della versione

Le sezioni seguenti descrivono come attenuare i problemi di mancata corrispondenza della versione.

Usare Azure SDK BOM

Usare la versione stabile più recente Azure SDK BOM e non specificare Azure SDK e versioni delle dipendenze nel file POM. Se applicabile, usare Azure BOM Spring Boot.

Le dipendenze elencate nella distinta base Azure SDK vengono testate rigorosamente per evitare conflitti di dipendenza.

Evitare dipendenze non necessarie

Rimuovere le dipendenze, se possibile. In alcuni casi, un'applicazione ha dipendenze da più librerie che forniscono essenzialmente le stesse funzionalità. Tali dipendenze non necessarie espongono le applicazioni a vulnerabilità di sicurezza, conflitti di versione e costi di supporto e manutenzione.

Aggiorna le versioni delle dipendenze

Se il passaggio all'ultima Azure SDK BOM non è utile, identificare le librerie che causano conflitti e i componenti che li usano. Per altre informazioni, vedere la sezione Visualizzare un albero delle dipendenze più indietro in questo articolo. Provare ad eseguire l'aggiornamento a una versione più recente, che protegge dalle vulnerabilità di sicurezza e spesso offre nuove funzionalità, miglioramenti delle prestazioni e correzioni di bug.

Evitare il downgrade della versione Azure SDK perché potrebbe esporre l'applicazione a vulnerabilità e problemi noti.

Librerie di sfumature

A volte non esiste alcuna combinazione di librerie che interagiscono e l'ombreggiatura è l'ultima risorsa.

Annotazioni

L'ombreggiatura presenta svantaggi significativi: aumenta le dimensioni del pacchetto e il numero di classi nel classpath, rende difficile lo spostamento del codice e il debug, non riloca il codice JNI, interrompe la reflection e potrebbe violare le licenze di codice tra le altre cose. Deve essere utilizzato solo dopo l'esaurimento di altre opzioni.

L'ombreggiatura consente di includere le dipendenze all'interno di un file JAR in fase di compilazione, quindi rinominare i pacchetti e aggiornare il codice dell'applicazione per usare il codice nel percorso ombreggiato. Il conflitto di dipendenze a rombo non è più un problema perché ci sono due copie differenti di una dipendenza. È possibile oscurare una libreria che ha una dipendenza transitiva in conflitto o una dipendenza diretta dell'applicazione, come descritto nel seguente elenco:

  • Conflitto di dipendenzetransitive: ad esempio, la libreria di terze parti A richiede Jackson 2.9, che Azure SDKs non supporta e non è possibile aggiornare A. Creare un nuovo modulo, che include A e shades (riloca) Jackson 2.9 e, facoltativamente, altre dipendenze di A.
  • Conflitto di dipendenze dell'applicazione: l'applicazione usa direttamente Jackson 2.9. Mentre lavori per aggiornare il tuo codice, puoi spostare e rilocare Jackson 2.9 in un nuovo modulo con classi Jackson rilocate.

Annotazioni

La creazione di jar fat con classi Jackson rilocate non risolve un conflitto di versione in questi esempi, ma forza solo una singola versione ombreggiata di Jackson.

Creare un file JAR grasso

Gli ambienti come Databricks o Apache Spark hanno una gestione delle dipendenze personalizzata e forniscono librerie comuni come Jackson. Per evitare conflitti con le librerie fornite, è possibile creare un file JAR fat contenente tutte le dipendenze. Per altre informazioni, vedere Plug-in Apache Maven Shade. In molti casi, la rilocazione delle classi Jackson (com.fasterxml.jackson) riduce il problema. In alcuni casi tali ambienti comportano anche la propria versione di Azure SDKs, pertanto potrebbe essere necessario spostare lo spazio dei nomi com.azure per risolvere i conflitti di versione.

Comprendere le versioni delle dipendenze compatibili

Per informazioni sulle dipendenze specifiche azure-core e sulle relative versioni, vedere azure-core al Maven Central Repository. La tabella seguente illustra alcune considerazioni generali:

Dipendenza Versioni supportate
Jackson 2.10.0 e versioni secondarie più recenti sono compatibili. Per altre informazioni, vedere la sezione Supporto per più versioni di Jackson .
SLF4J 1.7.*
netty-tcnative-boringssl-static 2.0.*
netty-common 4.1.*
nucleo del reattore 3.X.* - I numeri di versione principale e secondaria devono corrispondere esattamente a quelli da cui dipende la versione azure-core . Per ulteriori informazioni, vedere la policy di Project Reactor sulle deprecazioni.

Supporto per più versioni di Jackson

Il Azure SDK per Java supporta l'uso di una serie di versioni di Jackson. La versione più bassa supportata è Jackson 2.10.0. Il Azure SDK per le librerie client di Java regola la configurazione e l'utilizzo di Jackson a seconda della versione rilevata in fase di esecuzione. Questa regolazione consente una maggiore compatibilità con le versioni precedenti di Spring Framework, Apache Spark e altri ambienti comuni. Le applicazioni possono effettuare il downgrade delle versioni di Jackson (alla versione 2.10.0 o successiva) senza interrompere Azure SDK per le librerie client Java.

Annotazioni

L'uso di versioni precedenti di Jackson può esporre applicazioni a vulnerabilità e problemi noti. Per altre informazioni, vedere l'elenco delle vulnerabilità note per le librerie Jackson.

Quando si aggiunge una versione specifica di Jackson, assicurarsi di eseguire questa operazione per tutti i moduli usati da Azure SDK, visualizzati nell'elenco seguente:

  • jackson-annotations
  • jackson-core
  • jackson-databind
  • jackson-dataformat-xml
  • jackson-datatype-jsr310

Migrazione da Jackson a azure-json

Azure librerie client per Java sono in fase di migrazione a azure-json, che non dipende da componenti di terze parti e offre primitive condivise, astrazioni e helper per JSON.

Gli ambienti come Apache Spark, Apache Flink e Databricks potrebbero portare versioni precedenti di azure-core che non dipendono ancora da azure-json. Di conseguenza, quando si usano versioni più recenti di librerie di Azure in tali ambienti, è possibile che si verifichino errori simili a java.lang.NoClassDefFoundError: com/azure/json/JsonSerializable. È possibile attenuare questo errore aggiungendo una dipendenza esplicita da azure-json.

Passaggi successivi

Ora che si ha familiarità con i conflitti di versione delle dipendenze e come risolverli, vedere Dependency Management per Java per informazioni sul modo migliore per prevenirli.