2012-04-02 12 views
6

Spring dispone del buon meccanismo PropertyPlaceholderConfigurer per l'immissione di valori come timeout, URL JDBC e così via in bean Spring per scopi di configurazione. Esiste un modo ragionevole per gestire i valori di configurazione che possono cambiare in fase di esecuzione?Spring: come eseguire la configurazione di proprietà modificabili runtime trasparente

AGGIORNAMENTO: Con Spring 3.1 è possibile includere sorgenti di configurazione non statiche come il database tramite PropertySource s. Alcuni ApplicationContexts forniscono un meccanismo di aggiornamento che, in linea di principio, è in grado di gestire i cambiamenti dei valori di configurazione. Tuttavia, interrompe prima l'applicazione, quindi crea tutti i bean freschi e quindi riavvia il contesto dell'applicazione. Tuttavia, per i nostri scopi avrei bisogno di un modo per farlo in modo trasparente, in modo tale che il server gestisca correttamente le richieste attualmente in esecuzione.

Un'altra idea per farlo sarebbe un ambito personalizzato che crea nuovi oggetti quando la configurazione cambia. Sfortunatamente l'ObjectFactory fornito allo Scope utilizza una definizione di bean preelaborata, in modo tale che i segnaposto non vengano letti di nuovo dalla configurazione. Quindi gli oggetti creati hanno la stessa configurazione. :-(

+0

Probabilmente un modo per farlo sarebbe utilizzare un PropertyOverrideConfigurer http://stackoverflow.com/a/595201/21499, ma penso che il meccanismo di override della proprietà sia piuttosto scomodo da usare e soggetto a errori. –

risposta

2

Quanto segue è un po 'strano ma funziona. Si crea un reconfigurable che getta via tutti i bean creati in tale ambito ogni volta che si verifica un aggiornamento di configurazione. Quindi, un nuovo bean verrà creato dopo una modifica alla configurazione.

I valori di configurazione effettivi devono essere recuperati tramite linguaggio di espressione molla poiché i valori sia per la normale sintassi $ {} che per PropertyOverrideConfigurer sembrano essere permanentemente risolti nella BeanDefinition. Una dichiarazione di fagioli per un bean con una proprietà ri-configurabile someProperty assomiglia a questo:

<bean class="blablu.Testbean" scope="reconfigurable" 
    p:someProperty="#{ config['configexplicit']}"> 
    <aop:scoped-proxy /> 
</bean> 

è necessario utilizzare AOP: ambito-proxy in modo tale che i fagioli che usano questo fagiolo recuperare sempre il fagiolo fresco configurato dal campo di applicazione personalizzata .

Anche la dichiarazione delle proprietà con @Value funziona; se si utilizza la scansione dei componenti è necessario dichiarare la portata con l'annotazione

@Scope(value="reconfigurableScope", proxyMode=ScopedProxyMode.TARGET_CLASS) 

Se si cura per i dettagli: l'idea di fondo del campo di applicazione è:

public class ReconfigurableScope implements Scope { 

    private final Map<String, Object> nameToObjectMap = new ConcurrentHashMap<String, Object>(); 

    public Object get(final String name, final ObjectFactory<?> objectFactory) { 
     Object bean = nameToObjectMap.get(name); 
     if (null == bean) { 
      bean = objectFactory.getObject(); 
      nameToObjectMap.put(name, bean); 
     } 
     return bean; 
    } 

    // called from outside on each configuration change 
    public void update(final ConfigurationObservable observable, final Object arg) { 
     nameToObjectMap.clear(); 
    } 

} 

Inoltre alcune cose filo di sicurezza e di pulizia: i fagioli rimossi devono essere distrutti un po 'più tardi e nel contesto dell'applicazione chiusa.

+0

Qualsiasi esempio di codice sorgente dell'ambito personalizzato è possibile? :) – Kakawait

2

Purtroppo configurazione da properties file è statica e accade all'avvio Quello che sto facendo è in genere di esporre attributi dinamici via :.

@ManagedResource 
@Service 
public class BusinessService { 

    @ManagedAttribute 
    private int age; 

    public int getAge() { 
     return age; 
    } 

    public void setAge(int age) { 
     this.age = age; 
    } 

    public void businessMethod() { 
     //use age... 
    } 

} 

ricordarsi di aggiungere:

<context:mbean-export/> 

Per la tua configurazione. Ora puoi accedere e modificare l'attributo tramite jconsole o qualsiasi altro client JMX.Vedi anche: 23.3.2 Using Source-Level Metadata (JDK 5.0 annotations).

+0

I file delle proprietà non sono necessariamente statici: possono risiedere da qualche parte nel filesystem e essere modificati dalle operazioni. Hai ragione: si possono usare altri meccanismi per aggiornare i valori di configurazione, ma mi piacerebbe usare il simpatico meccanismo del segnaposto di Spring. Altrimenti, come aggiorneresti, per esempio, un timeout per un WebserviceTemplate senza molto codice di colla? –

+0

@hstoerr: wrt 'WebserviceTemplate' - richiede un po 'di codice colla anche quando non è necessario aggiornare nulla: http://onebyteatatime.wordpress.com/2009/03/19/how-to-set-socket-timeout -using-spring-webservicetemplate/e http://stackoverflow.com/questions/6733744 –

0

Per una riconfigurazione del runtime efficace, è possibile utilizzare il progetto Cloud Config di Spring. In questa disposizione, si dovrebbe avere un Configuration Repository, ad esempio un repository git, che contiene i valori di configurazione. Quindi metti un Configuration Server davanti a quel repository. Questo server verrebbe aggiornato ogni volta che si verifica un push nel repository di backup.Finalmente le tue app saranno clienti di quello Config Server e ne estrarranno le nuove configurazioni. Controlla Spring Cloud per maggiori dettagli.

1

C'è un esempio di esecuzione di ciò che si sta cercando di realizzare qui: https://github.com/ldojo/spring-cloud-config-examples

Si dimostra come un Cloud Server Config primavera e un servizio client possono comunicare oltre lo Spring nube autobus, e le proprietà di configurazione del cliente può cambiare in fase di esecuzione quando si verifica una modifica della configurazione nel repository del server di configurazione.

Problemi correlati