2009-09-28 15 views
11

Tengo dos archivos XML que define los granos para el Spring Framework (versión 2.5.x):Cómo modificar beans definidos en un contenedor de primavera

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

... y

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

Ahora Quiero ajustar la propiedad sourceCodeLocations de bean codebase dentro de containerSpecial.xml. Necesito agregar un segundo valor src/generated/productive.

Un enfoque simple es para anular la definición de codebase en containerSpecial.xml y añadir ambos valores, el de containerBase.xml y el nuevo:

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> 

¿Hay una manera de ampliar la lista sin redefinir ¿el frijol?

EDITAR 2009-10-06:

El propósito de esto es tener un contenedor estándar compartida containerBase que es utilizado por una gran cantidad de diferentes proyectos. Cada proyecto puede anular/extender algunas propiedades que son especiales para ese proyecto en su propio containerSpecial. Si el proyecto no sobrescribe, está usando los valores predeterminados definidos en containerBase.

Respuesta

8

Puede usar BeanFactoryPostProcessor para cambiar los metadatos del bean antes de que el contenedor Spring cree una instancia del bean CodeBase. Por ejemplo:

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; 
    } 

} 

Luego, 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 no es exactamente lo que estoy buscando, pero con este enfoque podría escribir CodebaseListExtender fácilmente. Lo intentaré. – tangens

3

Sí. Una definición de bean puede tener un atributo "principal" que hace referencia a una definición de bean padre. La nueva definición "secundaria" hereda la mayoría de las propiedades del elemento primario y cualquiera de esas propiedades puede anularse.

Ver Bean Definition Inheritance

También se puede usar para fusionar Collection Merging la definición de lista de propiedades de las definiciones de los padres y de frijol niño. De esta forma, puede especificar algunos elementos de lista en la definición de bean padre y agregarle más elementos en la definición de bean hijo.

+0

Pero luego hay dos frijoles. "codebase" y el de "containerSpecial.xml". De la aplicación solo quiero encontrar un frijol. Y no quiero hacer el "código base" de beans en el extracto "containerBase.xml", porque es necesario desde otro lugar. – tangens

+0

No tiene que nombrar ambas "bases de código" de beans, pueden tener nombres únicos. Además, no es necesario que haga el resumen de bean padre que no es un requisito, solo una opción. – kdubb

+0

Por cierto, también necesita buscar "recolección-fusión". Resuelve el problema de tener que volver a especificar los elementos de la colección que ya están especificados en la definición del bean padre. – kdubb

1

3 enfoques:

  1. simples: tener dos listas y defaultSourceCodeLocations additionalSourceCodeLocations y tienen sus métodos de acceso comprobar ambos (o combinarlos). He visto esto hecho en algunos marcos: se completa una lista predeterminada de controladores y se agregan otros creados por el usuario ...

  2. Más complicado pero mantiene limpia la clase original: podría crear una clase CodeBaseModifier. Esto tendría un método init para alterar una instancia inyectada del 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 quería hacer esto en realidad genérica que podría hacer un modificador de frijol que hacer esto mediante la reflexión. Tenga cuidado con el orden si usa este enfoque. Los beans dependientes de CodeBase tendrían que asegurarse de que esta clase se instanciara primero (con depende de)

3 Una variación de 2 ... En lugar de crear directamente una clase CodeBase, en su lugar cree una fábrica que devuelva un bean llenado. Esta fábrica podría configurarse con Spring de forma similar a 2.Tener un defaultSourceCodeLocations y additionalSourceCodeLocations

A menos que necesite una gran cantidad de propiedades extensibles Me gustaría ir con la opción 1.

+0

Lo siento, no puedo obtener el formato correcto ... – Pablojim

1

¿Hay una manera de definir la lista de inmueble u otra configuración antes de mano?

Parece que la configuración de la aplicación y el cableado están estrechamente conectados. Según mi experiencia, si es difícil hacer algo en primavera, es probable que haya una manera diferente y más fácil de hacerlo.

+0

Soy libre lo hago de la mejor manera. ¿Tienes una idea? – tangens

+0

Los archivos de propiedades son una configuración de sistema simple y se pueden inyectar en los granos de primavera a través de los objetos Propiedades. Los he usado para propiedades por defecto/contenedor similares. Para obtener soporte para la lista, delegue un método para analizar la lista desde el objeto Propiedades. config.default.properties --------------------------- source.locations.1 = src/handmade/productivo fuente .locations.2 = src/handmade/productive1 config.container.properties --------------------------- fuente. locations.1 = src/contenedor/productivo source.locations.2 = src/container/productive1 – jon077

Cuestiones relacionadas