Condividi tramite


Risolvere i conflitti di versione delle dipendenze

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

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

Molte applicazioni e framework Java usano queste librerie direttamente o transitivamente, che causano 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 lo strumento di compilazione azure SDK per Java

Lo strumento di compilazione azure SDK per Java, introdotto in Introduzione ad Azure SDK e Apache Maven, consente di identificare i problemi comunemente 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 Funzioni di Azure

La versione di dipendenza interna in Funzioni di Azure (che esegue 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 di Azure (v2 o v3) alla versione più recente.

Annotazioni

Questa configurazione si applica solo a Funzioni di Azure che eseguono Java 8, Funzioni che eseguono Java 11 non richiedono una configurazione speciale.

Configurare Apache Spark

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 Azure SDK per Java, gli sviluppatori spesso rilevano 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 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 di 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 in 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 Supporto per più versioni di Jackson .

Attenuare i problemi di mancata corrispondenza della versione

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

Usare il BOM (Bill of Materials) di Azure SDK

Usare l'ultima versione stabile di Azure SDK e non specificare le versioni di Azure SDK e delle dipendenze nel file POM. Se applicabile, usare il Azure Spring Boot BOM.

Le dipendenze elencate nel BOM di 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 passare alla versione più recente di Azure SDK BOM non dovesse essere utile, identificare le librerie che causano conflitti e i componenti che le 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 di 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 dipendenze transitive: ad esempio, la libreria A di terze parti richiede Jackson 2.9, che gli SDK di Azure non supportano 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 degli SDK di Azure, quindi potrebbe essere necessario spostare com.azure lo spazio dei nomi 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

Azure SDK per Java supporta l'uso di una gamma di versioni Jackson. La versione più bassa supportata è Jackson 2.10.0. Le librerie client di Azure SDK per Java regolano 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 jackson (alla versione 2.10.0 o successiva) senza interrompere le librerie client di Azure SDK per 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

Le librerie client di Azure per Java sono in fase di migrazione ad azure-json, che non dipende da alcun componente di terze parti e offre primitive, astrazioni e helper condivisi 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 delle 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 su come risolverli, vedere Gestione delle dipendenze per Java per informazioni sul modo migliore per evitarli.