Share via


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 consumer 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 della 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.

Nota

Questa configurazione si applica solo a Funzioni di Azure che esegue 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.

Nota

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 la distinta base di Azure SDK

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

Le dipendenze elencate nella distinta base 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.

Aggiornare le versioni delle dipendenze

Se si passa alla versione più recente di Azure SDK BOM non è utile, identificare le librerie che causano conflitti e i componenti che li usano. Per altre informazioni, vedere Visualizzare una sezione relativa all'albero delle dipendenze in precedenza 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 shade

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

Nota

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 rombo non è più un problema perché sono presenti due copie diverse di una dipendenza. È possibile ombreggiatura di una libreria con una dipendenza transitiva in conflitto o una dipendenza diretta dell'applicazione, come descritto nell'elenco seguente:

  • 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 si sta lavorando per aggiornare il codice, è possibile ombreggiatura e rilocare Jackson 2.9 in un nuovo modulo con classi Jackson rilocate.

Nota

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.

Informazioni sulle versioni delle dipendenze compatibili

Per informazioni sulle azure-coredipendenze specifiche e sulle relative versioni, vedere azure-core nel repository centrale Maven. La tabella seguente illustra alcune considerazioni generali:

Dependency 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.*
reattore-core 3.X.* - I numeri di versione principale e secondaria devono corrispondere esattamente a quelli da cui dipende la versione azure-core . Per altre informazioni, vedere i criteri di Project Reactor sulle deprecate.

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.

Nota

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

Passaggi successivi

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