2009-09-28 6 views
11

J'ai deux fichiers xml définissant les haricots pour la springframework (version 2.5.x):Comment modifier les haricots définis dans un récipient à ressort

containerBase.xml: 
<beans> 
    <bean id="codebase" class="com.example.CodeBase"> 
     <property name="sourceCodeLocations"> 
      <list> 
       <value>src/handmade/productive</value> 
      </list> 
     </property> 
    </bean> 
</beans> 

... et

containerSpecial.xml: 
<beans> 
    <import resource="containerBase.xml" /> 
</beans> 

maintenant Je veux régler la propriété sourceCodeLocations de haricot codebase au sein de containerSpecial.xml. Je dois ajouter une deuxième valeur src/generated/productive.

Une approche simple est de passer outre la définition de codebase dans containerSpecial.xml et ajoutez les deux valeurs, celle de containerBase.xml et le nouveau:

containerSpecial.xml: 
<beans> 
    <import resource="containerBase.xml" /> 

    <bean id="codebase" class="com.example.CodeBase"> 
     <property name="sourceCodeLocations"> 
      <list> 
       <value>src/handmade/productive</value> 
       <value>src/generated/productive</value> 
      </list> 
     </property> 
    </bean> 
</beans> 

Est-il possible d'étendre la liste sans redéfinir le haricot?

EDIT 2009-10-06:

Le but est d'avoir un conteneur standard partagé containerBase qui est utilisé par un grand nombre de projets différents. Chaque projet peut remplacer/étendre certaines propriétés spéciales pour ce projet dans son propre containerSpecial. Si le projet ne remplace pas, il utilise les valeurs par défaut définies dans containerBase.

Répondre

8

Vous pouvez utiliser un BeanFactoryPostProcessor pour modifier les métadonnées du bean avant que le conteneur Spring instancie le bean CodeBase. Par exemple:

public class CodebaseOverrider implements BeanFactoryPostProcessor { 

    private List<String> sourceCodeLocations; 

    public void postProcessBeanFactory(
      ConfigurableListableBeanFactory beanFactory) throws BeansException {   
     CodeBase codebase = (CodeBase)beanFactory.getBean("codebase"); 
     if (sourceCodeLocations != null) 
     { 
      codebase.setSourceCodeLocations(sourceCodeLocations); 
     } 
    } 

    public void setSourceCodeLocations(List<String> sourceCodeLocations) { 
     this.sourceCodeLocations = sourceCodeLocations; 
    } 

} 

Puis, en contextSpecial.xml:

<beans> 
    <import resource="context1.xml" /> 

    <bean class="com.example.CodebaseOverrider"> 
     <property name="sourceCodeLocations"> 
      <list> 
       <value>src/handmade/productive</value> 
       <value>src/generated/productive</value> 
      </list> 
     </property> 
    </bean> 
</beans> 
+0

CodebaseOverrider n'est pas tout à fait ce que je cherche, mais avec cette approche, je pourrais facilement écrire un CodebaseListExtender. Je vais l'essayer. – tangens

3

Oui. Une définition de bean peut avoir un attribut "parent" qui fait référence à une définition de bean parent. La nouvelle définition "enfant" hérite de la plupart des propriétés du parent et l'une de ces propriétés peut être remplacée.

Voir Bean Definition Inheritance

vous pouvez également utiliser Collection Merging pour fusionner la définition de la propriété de la liste des définitions des parents et des enfants haricots. De cette façon, vous pouvez spécifier certains éléments de la liste dans la définition du bean parent et y ajouter plus d'éléments dans la définition du bean enfant.

+0

Mais alors il y a deux haricots. "codebase" et celui dans "containerSpecial.xml". De l'application, je veux seulement trouver un haricot. Et je ne veux pas faire le bean "codebase" dans le résumé "containerBase.xml", parce qu'il est nécessaire d'ailleurs. – tangens

+0

Vous ne devez pas nommer les deux beans "codebase" ils peuvent avoir des noms uniques. De plus, vous n'avez pas besoin de faire le résumé du bean parent qui n'est pas une exigence, seulement une option. – kdubb

+0

Par ailleurs, vous devez également rechercher "collection-fusion". Il résout le problème de devoir spécifier à nouveau les éléments de collection déjà spécifiés dans la définition du bean parent. – kdubb

1

3 approches:

  1. simples: avoir deux listes defaultSourceCodeLocations et additionalSourceCodeLocations et que vos méthodes accesseurs vérifier ces deux (ou les combiner). J'ai vu cela dans certains frameworks - une liste par défaut de gestionnaires est remplie puis des utilisateurs supplémentaires sont ajoutés ...

  2. Plus compliqué mais garde la classe originale propre: Vous pouvez ensuite créer une classe CodeBaseModifier. Cela aurait une init-méthode pour modifier une instance injectée du bean.

    <bean id="codebaseModifier" class="com.example.CodeBase" init-method="populateCodeBase"> 
        <property name="sourceCodeLocations" ref="codebase"/> 
        <property name="additionalSourceCodeLocations"> 
        <list> 
         <value>src/handmade/productive</value> 
        </list> 
        </property> 
    </bean> 
    

Si vous voulez faire cela, vous vraiment générique pourrait faire un modificateur de haricot qui ferait cela par la réflexion. Faites attention à la commande si vous utilisez cette approche. Les beans dépendants de CodeBase doivent s'assurer que cette classe a été instanciée en premier (avec dépend)

3 Une variation sur 2 ... Au lieu de créer directement une classe CodeBase, créez plutôt une fabrique qui retourne un bean rempli. Cette usine pourrait alors être configurée avec Spring de manière similaire à 2.Avoir un defaultSourceCodeLocations et additionalSourceCodeLocations

Sauf si vous avez besoin de beaucoup de propriétés extensibles Je voudrais aller avec l'option 1.

+0

Désolé ne peut pas obtenir le formatage correct ... – Pablojim

1

Est-il possible de définir la liste des propriétés dans un ou une autre configuration avant la main?

Il semble que la configuration et le câblage de l'application soient étroitement liés. D'après mon expérience, s'il est difficile de faire quelque chose au printemps, il y a probablement une façon différente de le faire.

+0

Je suis libre le faire de la meilleure façon. Avez-vous une idée? – tangens

+0

Les fichiers de propriétés sont une configuration système simple et peuvent être injectés dans des haricots de printemps via des objets Propriétés. Je les ai utilisés pour des propriétés par défaut/conteneur similaires. Pour obtenir le support de liste, déléguez une méthode pour analyser la liste à partir de l'objet Properties. config.default.properties --------------------------- source.locations.1 = src/handmade/productif source .locations.2 = src/handmade/productif1 config.container.properties ------------------------- source. locations.1 = src/container/productif source.locations.2 = src/container/productive1 – jon077