2010-11-03 6 views
5

Ho un file delle proprietà e utilizzo il titolare della posizione della proprietà Spring, ho impostato i valori sui bean Spring. Ora, questo file delle proprietà può essere modificato durante il tempo di esecuzione. C'è un modo per aggiornare le proprietà dei bean Spring con questo valore di proprietà appena modificato? Soprattutto, ho molti fagioli singleton? Come posso aggiornarli con i nuovi valori? C'è già una soluzione o dovrebbe essere personalizzata? Se non esiste già, qualcuno può per favore dare l'approccio migliore per raggiungere questo obiettivo? Grazie!Spring - Sostituzione dei valori delle proprietà del bean con i nuovi valori del file delle proprietà

PS: La mia domanda è un'applicazione batch. Uso la configurazione Quartz basata sulla primavera per pianificare i lotti.

risposta

3

Lascio questo riferimento, ma la risposta aggiornato è al di sotto del divisore:

Bene l'interfaccia ConfigurableApplicationContext contiene un metodo refresh(), che dovrebbe essere ciò che si vuole, ma la domanda è: come accedere quel metodo. In qualunque modo lo si fa, si inizia con un fagiolo che ha una dipendenza di tipo ConfigurableApplicationContext:

private ConfigurableApplicationContext context; 
@Autowired 
public void setContext(ConfigurableApplicationContext ctx){ 
    this.context = ctx; 
} 

Ora le due opzioni di base io suggerirei sarebbe a uno

  1. utilizzare il Task Execution Framework e lascia che il tuo bean controlli regolarmente le risorse della proprietà, aggiornando ApplicationContext quando trova le modifiche o
  2. expose the bean to JMX, consentendo di attivare manualmente l'aggiornamento.

riferisco a commenti: poiché sembra impossibile aggiornare l'intero contesto, una strategia alternativa potrebbe essere quella di creare un chicco di proprietà fabbrica e iniettare che in tutte le altre fagioli.

public class PropertiesFactoryBean implements FactoryBean<Properties>{ 

    public void setPropertiesResource(Resource propertiesResource){ 
     this.propertiesResource = propertiesResource; 
    } 

    private Properties value=null; 
    long lastChange = -1L; 

    private Resource propertiesResource; 

    @Override 
    public Properties getObject() throws Exception{ 
     synchronized(this){ 
      long resourceModification = propertiesResource.lastModified(); 
      if(resourceModification != lastChange){ 
       Properties newProps = new Properties(); 
       InputStream is = propertiesResource.getInputStream(); 
       try{ 
        newProps.load(is); 
       } catch(IOException e){ 
        throw e; 
       } finally{ 
        IOUtils.closeQuietly(is); 
       } 
       value=newProps; 
       lastChange= resourceModification; 
      } 
     } 
     // you might want to return a defensive copy here 
     return value; 
    } 

    @Override 
    public Class<?> getObjectType(){ 
     return Properties.class; 
    } 

    @Override 
    public boolean isSingleton(){ 
     return false; 
    } 

} 

Si potrebbe iniettare gli annunci di questo fagiolo in tutti gli altri fagioli, tuttavia, si dovrà fare attenzione ad usare sempre prototipo ambito. Questo è particolarmente difficile all'interno dei fagioli singleton, a solution can be found here.

Se non si vuole iniettare metodi di ricerca in tutto il luogo, si potrebbe anche iniettare un PropertyProvider fagioli come questo:

public class PropertiesProvider implements ApplicationContextAware{ 

    private String propertyBeanName; 
    private ApplicationContext applicationContext; 

    public void setPropertyBeanName(final String propertyBeanName){ 
     this.propertyBeanName = propertyBeanName; 
    } 

    @Override 
    public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException{ 
     this.applicationContext = applicationContext; 
    } 

    public String getProperty(final String propertyName){ 
     return ((Properties) applicationContext.getBean(propertyBeanName)).getProperty(propertyName); 
    } 

} 
+0

Non sarebbe questo carico l'intero contesto di applicazione? Potete per favore condividere qualche campione? Sono abbastanza nuovo per Spring, quindi potrei sbagliarmi. Ho anche pensato di ricaricare l'intero contesto applicativo di primavera, ma ciò significherebbe che altri processi attualmente in esecuzione potrebbero essere interrotti. O forse sto pensando male! – SJoe

+0

No, hai ragione, il contesto completo sarebbe stato aggiornato. –

+0

In tal caso, il mio processo in corso non verrà interrotto. Il mio è un'applicazione batch e potrebbe richiedere ore per completare un processo. Inoltre, ho un SchedularFactoryBean configurato tramite Spring. La mia domanda è, se ricarico completamente il contesto dell'applicazione, lo scheduler non dovrebbe essere ripristinato? – SJoe