Come posso scrivere un’applicazione Java in grado di aggiornarsi in fase di runtime?

Vorrei implementare un’applicazione java (applicazione server) in grado di scaricare una nuova versione (file .jar) da un determinato url e quindi aggiornarsi al runtime.

Qual è il modo migliore per farlo ed è ansible?

Immagino che l’applicazione possa scaricare un nuovo file .jar e avviarlo. Ma come dovrei fare il passaggio di consegne, ad esempio sapere quando viene avviata la nuova applicazione e poi uscire. O c’è un modo migliore per farlo?

La struttura di base di una soluzione è la seguente:

  • C’è un ciclo principale responsabile del caricamento ripetuto della versione più recente dell’app (se necessario) e del suo avvio.

  • L’applicazione fa la sua cosa, ma controlla periodicamente l’URL di download. Se rileva una nuova versione, ritorna al programma di avvio.

Ci sono diversi modi in cui potresti implementarlo. Per esempio:

  • Il programma di avvio può essere uno script wrapper o un’applicazione binaria che avvia una nuova JVM per eseguire l’applicazione da un file JAR che viene sostituito.

  • Il programma di avvio può essere un’applicazione Java che crea un classloader per il nuovo JAR, carica una class entrypoint e chiama un metodo su di esso. Se lo fai in questo modo, devi controllare le perdite di archiviazione del classloader, ma non è difficile. (Devi solo assicurarti che nessun object con le classi caricate dal JAR sia raggiungibile dopo il tuo riavvio.)

I vantaggi dell’approccio wrapper esterno sono:

  • hai solo bisogno di un JAR,
  • puoi sostituire l’intera app Java,
  • eventuali thread secondari creati dall’app, ecc. andranno via senza una speciale logica di spegnimento, e
  • puoi anche gestire il ripristino da arresti anomali dell’applicazione, ecc.

Il secondo approccio richiede due JAR, ma presenta i seguenti vantaggi:

  • la soluzione è pura Java e portatile,
  • il passaggio sarà più veloce, e
  • è ansible conservare più facilmente lo stato durante il riavvio (problemi di perdita modulo).

Il modo “migliore” dipende dalle tue esigenze specifiche.

Va anche notato che:

  • Ci sono rischi per la sicurezza con l’auto-aggiornamento. In generale, se il server che fornisce gli aggiornamenti è compromesso, o se i meccanismi per fornire gli aggiornamenti sono suscettibili di attacco, l’aggiornamento automatico può comportare una compromissione dei client.

  • L’invio di un aggiornamento a un cliente che causa danni al cliente potrebbe comportare rischi legali e rischi per la reputazione dell’azienda.


Se riesci a trovare un modo per evitare di reinventare la ruota, sarebbe bello. Vedi le altre risposte per i suggerimenti.

Attualmente sto sviluppando un demone Linux JAVA e ho anche avuto la necessità di implementare un meccanismo di aggiornamento automatico. Volevo limitare la mia applicazione a un file jar e ho trovato una soluzione semplice:

Imballare l’applicazione di aggiornamento nell’aggiornamento stesso.

Applicazione : quando l’applicazione rileva una versione più recente, effettua le seguenti operazioni:

  1. Scarica l’aggiornamento (Zipfile)
  2. Estrai applicazione e ApplicationUpdater (tutto nel file zip)
  3. Esegui il programma di aggiornamento

ApplicationUpdater : quando viene eseguito il programma di aggiornamento, procede come segue:

  1. Arresta l’applicazione (nel mio caso un demone tramite init.d)
  2. Copia il file jar scaricato per sovrascrivere l’applicazione corrente
  3. Avvia l’applicazione
  4. Pulire.

Spero che aiuti qualcuno.

Ho scritto un’applicazione Java in grado di caricare plugin in fase di runtime e iniziare a usarli immediatamente, ispirato a un meccanismo simile in jEdit. jEdit è open source quindi hai la possibilità di vedere come funziona.

La soluzione utilizza un ClassLoader personalizzato per caricare i file dal jar. Una volta caricati, puoi invocare un metodo dal nuovo jar che fungerà da metodo main . Quindi la parte difficile è assicurarsi di eliminare tutti i riferimenti al vecchio codice in modo che possa essere raccolto. Non sono abbastanza esperto da quella parte, l’ho fatto funzionare ma non è stato facile.

Questo è un problema noto e ti consiglio di non reinventare una ruota: non scrivere il tuo hack, basta usare quello che altre persone hanno già fatto.

Due situazioni che devi considerare:

  1. L’app deve essere autoaggiornabile e continuare a essere eseguita anche durante l’aggiornamento (app del server, app integrate). Vai con OSGi: Bundles o Equinox p2 .

  2. App è un’app desktop e ha un programma di installazione. Ci sono molti programmi di installazione con l’opzione di aggiornamento. Controlla la lista degli installatori .

  1. Primo modo: usa Tomcat e le sue strutture di distribuzione.
  2. Secondo modo: dividere l’applicazione su due parti (funzionale e aggiornamento) e aggiornare la parte della funzione sostituisci parte.
  3. Terzo modo: nella tua applicazione server basta scaricare la nuova versione, quindi la vecchia versione rilascia la porta associata, quindi la vecchia versione esegue la nuova versione (avvia il processo), quindi la vecchia versione invia una richiesta sulla porta dell’applicazione alla nuova versione per eliminare la vecchia versione, vecchia versione termina e la nuova versione cancella la vecchia versione. Come questo: alt text

Ho recentemente creato update4j che è completamente compatibile con il sistema modulare di Java 9.

Avvia senza problemi la nuova versione senza un riavvio.

Questo non è necessariamente il modo migliore , ma potrebbe funzionare per te.

Puoi scrivere un’applicazione di bootstrap (ad esempio, il launcher di World of Warcraft, se hai giocato a WoW). Quel bootstrap è responsabile del controllo degli aggiornamenti.

  • Se è disponibile un aggiornamento, lo offrirà all’utente, gestirà il download, l’installazione, ecc.
  • Se l’applicazione è aggiornata, consentirà all’utente di avviare l’applicazione
  • Facoltativamente, puoi consentire all’utente di avviare l’applicazione, anche se non è aggiornata

In questo modo non devi preoccuparti di forzare un’uscita della tua applicazione.

Se l’applicazione è basata sul Web e se è importante che dispongano di un client aggiornato, è inoltre ansible eseguire controlli di versione durante l’esecuzione dell’applicazione. È ansible eseguirli a intervalli, mentre si eseguono normali comunicazioni con il server (alcune o tutte le chiamate) o entrambe.

Per un prodotto su cui ho lavorato di recente, abbiamo eseguito verifiche delle versioni al momento del lancio (senza app di boot strapper, ma prima che appaia la finestra principale) e durante le chiamate al server. Quando il cliente non era aggiornato, ci affidavamo all’utente per uscire manualmente, ma vietava qualsiasi azione contro il server.

Si noti che non so se Java può richiamare il codice dell’interfaccia utente prima di aprire la finestra principale. Stavamo usando C # / WPF.

Se si crea l’applicazione utilizzando i plug-in Equinox , è ansible utilizzare il P2 Provisioning System per ottenere una soluzione pronta per questo problema. Ciò richiederà il riavvio del server stesso dopo un aggiornamento.

Vedo un problema di sicurezza durante il download di un nuovo barattolo (ecc.), Ad esempio un uomo nel mezzo dell’attacco. Devi sempre firmare il tuo aggiornamento scaricabile.

Su JAX2015, Adam Bien ha parlato dell’uso di JGit per l’aggiornamento dei binari. Purtroppo non ho trovato nessun tutorial.

Fonte in tedesco.

Adam Bien ha creato l’aggiornamento qui

L’ho biforcato qui con un frontend javaFX. Sto anche lavorando a una firma automatica.