68 votes

Puis-je remplacer une définition de bean Spring au moment de l'exécution?

Envisagez le scénario suivant. J'ai un Ressort de contexte de l'application avec un haricot dont les propriétés doivent être configurable, pense DataSource ou MailSender. La mutable configuration de l'application est gérée par un autre bean, appelons - configuration.

Un administrateur peut maintenant modifier les valeurs de configuration, comme l'adresse email ou de la base de données URL, et je tiens à re-initialiser la configuration de la fève au moment de l'exécution.

Supposons que je ne peux pas tout simplement modifier la propriété de l'configurable bean ci-dessus (par exemple, créé en FactoryBean ou le constructeur de l'injection) mais pour recréer le bean lui-même.

Des idées sur comment faire? Je serais heureux de recevoir des conseils sur la façon d'organiser l'ensemble de la configuration chose. Rien n'est fixe. :-)

MODIFIER

Pour clarifier un peu les choses: je ne demande pas comment faire pour mettre à jour la configuration ou comment injecter les valeurs de configuration statique. Je vais essayer un exemple:

<beans>
    <util:map id="configuration">
        <!-- initial configuration -->
    </util:map>

    <bean id="constructorInjectedBean" class="Foo">
        <constructor-arg value="#{configuration['foobar']}" />
    </bean>

    <bean id="configurationService" class="ConfigurationService">
        <property name="configuration" ref="configuration" />
    </bean>
</beans>

Donc, il y a un haricot constructorInjectedBean qui utilise le constructeur de l'injection. Imaginez la construction de la fève est très cher, donc à l'aide d'un prototype de portée ou d'une usine de proxy n'est pas une option, pensez DataSource.

Ce que je veux faire, c'est que chaque fois que la configuration est en cours de mise à jour (via configurationService le haricot constructorInjectedBean est recréé et ré-injectée dans le contexte de l'application et dépendante des haricots.

On peut supposer qu' constructorInjectedBean est à l'aide d'une interface proxy de la magie est en effet une option.

J'espère avoir fait de la question un peu plus clair.

29voto

Justin Points 2376

Voici comment je l'ai fait dans le passé: l'exécution des services qui dépendent de la configuration qui peut être changée à la volée en œuvre du cycle de vie de l'interface: IRefreshable:

public interface IRefreshable {
  // Refresh the service having it apply its new values.
  public void refresh(String filter);

  // The service must decide if it wants a cache refresh based on the refresh message filter.
  public boolean requiresRefresh(String filter);
}

Les contrôleurs (ou services) qui peut modifier un élément de configuration diffusion d'une rubrique JMS que la configuration a été modifiée (fournissant le nom de l'objet de configuration). Un message driven bean invoque ensuite la IRefreshable interface de contrat sur tous les grains de mettre en œuvre IRefreshable.

La bonne chose avec le printemps, c'est que vous pouvez détecter automatiquement toute service dans votre contexte de l'application qui doit être actualisé, en supprimant la nécessité de configurer explicitement:

public class MyCacheSynchService implements InitializingBean, ApplicationContextAware {
 public void afterPropertiesSet() throws Exception {
  Map<String, ?> refreshableServices = m_appCtx.getBeansOfType(IRefreshable.class);
  for (Map.Entry<String, ?> entry : refreshableServices.entrySet() ) {
   Object beanRef = entry.getValue();
   if (beanRef instanceof IRefreshable) {
    m_refreshableServices.add((IRefreshable)beanRef);
   }
  }
 }
}

Cette approche fonctionne particulièrement bien dans une application en cluster où l'un des nombreux serveurs d'application possible de modifier la configuration, qui tous doivent être conscients de. Si vous souhaitez utiliser JMX que le mécanisme de déclenchement de la modification, votre JMX haricot peut ensuite diffusé à la rubrique JMS lorsque l'un quelconque de ses attributs sont modifiés.

12voto

shrini1000 Points 2011

Je peux penser à une approche de «titulaire de haricot» (essentiellement un décorateur), où le titulaire de haricot délègue un titulaire à un titulaire, et c’est le haricot de titulaire qui est injecté en tant que dépendance à d’autres haricots. Personne d'autre n'a de référence à titulaire, à l'exception du titulaire. Désormais, lorsque la configuration du bean holder est modifiée, le titulaire est recréé avec cette nouvelle configuration et commence à déléguer.

11voto

mR_fr0g Points 3534

Vous devriez jeter un oeil à JMX. Spring fournit également un soutien pour de cette.

2voto

Gary Rowe Points 4220

Nouvelle mise à jour de répondre à couvrir script bean

Une autre approche soutenue par spring 2.5.x+ est que le script de la fève. Vous pouvez utiliser une variété de langues pour votre script BeanShell est probablement la plus intuitive étant donné qu'elle a la même syntaxe que Java, mais elle nécessite des dépendances externes. Cependant, les exemples sont en Groovy.

Section 24.3.1.2 du Ressort de la Documentation traite de la façon de le configurer, mais voici quelques saillants extraits illustrant l'approche que j'ai édité pour les rendre plus applicable à votre situation:

<beans>

    <!-- This bean is now 'refreshable' due to the presence of the 'refresh-check-delay' attribute -->
    <lang:groovy id="messenger"
          refresh-check-delay="5000" <!-- switches refreshing on with 5 seconds between checks -->
          script-source="classpath:Messenger.groovy">
        <lang:property name="message" value="defaultMessage" />
    </lang:groovy>

    <bean id="service" class="org.example.DefaultService">
        <property name="messenger" ref="messenger" />
    </bean>

</beans>

Avec le Groovy script comme ceci:

package org.example

class GroovyMessenger implements Messenger {

    private String message = "anotherProperty";

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message
    }
}

L'administrateur de système veut faire des changements alors qu'ils (ou vous) pouvez modifier le contenu du script de façon appropriée. Le script ne fait pas partie de l'application déployée et peut faire référence à un fichier connu (ou celui qui est configuré par le biais d'un PropertyPlaceholderConfigurer pendant le démarrage).

Bien que l'exemple utilise une classe Groovy, vous pourriez avoir la classe à exécuter du code qui lit un simple fichier de propriétés. De cette façon, vous ne jamais modifier le script directement, il suffit de toucher pour changer l'heure et la date. Cette action déclenche alors la recharger, ce qui déclenche à son tour l'actualisation des propriétés de l' (mise à jour) le fichier de propriétés qui, enfin, met à jour les valeurs dans le Ressort du contexte et vous partez.

La documentation ne souligner que cette technique ne fonctionne pas pour le constructeur injection, mais peut-être que vous pouvez travailler autour de cela.

Mise à jour de la réponse à la couverture dynamique des changements de propriété

Citation de cet article, qui fournit l'intégralité du code source, une approche est la suivante:

* a factory bean that detects file system changes
* an observer pattern for Properties, so that file system changes can be propagated
* a property placeholder configurer that remembers where which placeholders were used, and updates singleton beans' properties
* a timer that triggers the regular check for changed files

L'observateur modèle est mis en œuvre par les interfaces et les classes ReloadableProperties, ReloadablePropertiesListener, PropertiesReloadedEvent, et ReloadablePropertiesBase. Aucun d'entre eux sont particulièrement passionnants, tout à fait normal auditeur de la manipulation. La classe DelegatingProperties sert à de manière transparente à l'échange de l'actuel propriétés lorsque les propriétés sont mis à jour. Nous n'mise à jour de l'ensemble de la carte de propriété à la fois, de sorte que le l'application peut éviter des incohérences les états intermédiaires (plus sur cela plus tard).

Maintenant, le ReloadablePropertiesFactoryBean peut être écrit pour créer un ReloadableProperties instance (au lieu une des Propriétés de l'instance, comme le PropertiesFactoryBean n'). Lorsque vous êtes invité à le faire, le RPFB vérifie la modification de fichier de fois, et si nécessaire, mises à jour de ses ReloadableProperties. Cela déclenche le pattern observer des machines.

Dans notre cas, le seul auditeur est l' ReloadingPropertyPlaceholderConfigurer. Il se comporte exactement comme un standard de printemps PropertyPlaceholderConfigurer, à l'exception de qu'il suit toutes les utilisations de l' des espaces réservés. Maintenant, lorsque les propriétés sont reloaded, tous les usages de chaque modifié propriété sont trouvés, et les propriétés de ces singleton haricots sont affectés de nouveau.

Réponse originale à cette question ci-dessous couvrant statiques des modifications de la propriété:

Des sons comme vous voulez juste pour injecter des propriétés externes dans votre Printemps contexte. L' PropertyPlaceholderConfigurer est prévu à cet effet:

  <!-- Property configuration (if required) -->
  <bean id="serverProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
      <list>
        <!-- Identical properties in later files overwrite earlier ones in this list -->
        <value>file:/some/admin/location/application.properties</value>
      </list>
    </property>
  </bean>

vous ensuite de référence externe propriétés avec Ant syntaxe des espaces réservés (qui peuvent être imbriquées, si vous voulez à partir du Printemps 2.5.5 à partir)

  <bean id="example" class="org.example.DataSource">
    <property name="password" value="${password}"/>
  </bean>

Veiller à ce que l'application.les propriétés de fichier n'est accessible qu'à l'administrateur et de l'utilisateur exécutant l'application.

Exemple d'application.propriétés:

mot de passe=Aardvark

2voto

Sean Patrick Floyd Points 109428

Ou vous pourriez utiliser l'approche de cette question similaire, et donc aussi ma solution:

L'approche est d'avoir des haricots qui sont configurés via les fichiers de propriété et la solution est soit de

  • actualisation de l'ensemble de l'applicationContext (automatiquement à l'aide d'une tâche planifiée manuellement ou à l'aide de JMX) lorsque les propriétés ont changé ou
  • utilisez un fournisseur de la propriété de l'objet pour accéder à toutes les propriétés. Cette propriété du fournisseur gardera la vérification des propriétés des fichiers pour les modifier. Pour les haricots, où prototype de base de recherche de propriété est impossible, enregistrer un événement personnalisé que votre propriété fournisseur d'incendie lorsqu'il détecte une mise à jour du fichier de propriétés. Vos haricots avec des cycles de vie aura besoin d'écouter pour cet événement et de se rafraîchir.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X