J'ai un fichier de propriétés et en utilisant le support de la propriété Spring, je définis les valeurs pour les beans Spring. Maintenant, ce fichier de propriétés peut être modifié pendant l'exécution. Est-il possible d'actualiser les propriétés des beans Spring avec cette valeur de propriété nouvellement modifiée? Surtout, j'ai beaucoup de haricots singleton? Comment puis-je les rafraîchir avec les nouvelles valeurs? Y a-t-il déjà une solution à cela ou devrait-elle être codée sur mesure? Si ce n'est pas déjà le cas, quelqu'un peut-il donner la meilleure approche pour y parvenir? Merci! PS: Mon application est une application par lots. J'utilise la configuration Quartz à base de printemps pour programmer les lots.Spring - Remplacement des valeurs des propriétés du bean par les nouvelles valeurs du fichier de propriétés
Répondre
Je vais laisser cela à titre de référence, mais la réponse est mis à jour en dessous du diviseur:
bien l'interface ConfigurableApplicationContext
contient une méthode refresh(), qui devrait être ce que vous voulez, mais la question est: comment accéder cette méthode. Quelle que soit la façon dont vous le faites, vous allez commencer avec un haricot qui a une dépendance de type ConfigurableApplicationContext
:
private ConfigurableApplicationContext context;
@Autowired
public void setContext(ConfigurableApplicationContext ctx){
this.context = ctx;
}
Maintenant, les deux options de base je proposerais serait soit
- utiliser le Task Execution Framework et laissez votre bean regarder les ressources de propriété régulièrement, en actualisant le ApplicationContext lorsqu'il trouve des modifications ou
- expose the bean to JMX, vous permettant de déclencher manuellement l'actualisation.
Faisant référence aux observations: car il semble impossible de rafraîchir tout le contexte, une stratégie alternative serait de créer un haricot d'usine de propriétés et injecter que dans tous les autres haricots.
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;
}
}
Vous pouvez injecter les annonces de haricots dans tous vos autres haricots, cependant, vous devez être prudent d'utiliser toujours la portée du prototype. Ceci est particulièrement difficile à l'intérieur des haricots singleton, a solution can be found here.
Si vous ne voulez pas injecter des méthodes de consultation dans tous les sens, vous pouvez aussi injecter un haricot PropertyProvider
comme ceci:
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);
}
}
Ne serait pas cette charge l'ensemble du contexte d'application? Pouvez-vous s'il vous plaît partager un échantillon? Je suis assez nouveau au printemps donc je peux me tromper. J'ai également pensé à recharger tout le contexte de l'application printanière, mais cela signifierait que d'autres processus en cours pourraient être perturbés. Ou peut-être que je pense mal! – SJoe
Non, vous avez raison, le contexte complet serait rafraîchi. –
Dans ce cas, mon processus en cours ne serait pas perturbé. Le mien est une application par lots et cela peut prendre des heures pour terminer un processus. De plus, j'ai un SchedularFactoryBean configuré à Spring. Ma question est la suivante: si je recharge complètement le contexte d'application, le planificateur ne serait-il pas réinitialisé? – SJoe