2012-04-02 16 views
6

Spring tiene el bonito mecanismo PropertyPlaceholderConfigurer para inyectar valores como tiempos de espera, URL de JDBC y otros en Spring beans para propósitos de configuración. ¿Hay una manera sensata de manejar los valores de configuración que pueden cambiar en el tiempo de ejecución?Spring: cómo hacer una configuración de propiedad variable de tiempo de ejecución transparente

ACTUALIZACIÓN: Con Spring 3.1 hay una buena manera de incluir fuentes de configuración no estáticas como la base de datos a través del PropertySource s. Algunos ApplicationContexts proporcionan un mecanismo de actualización que, en principio, puede manejar cambios en los valores de configuración. Sin embargo, detiene la aplicación primero, luego crea todos los beans frescos y luego vuelve a iniciar el contexto de la aplicación. Sin embargo, para nuestros propósitos, necesitaría una forma de hacerlo de forma transparente, de manera que el servidor maneje correctamente las solicitudes actualmente en ejecución.

Otra idea para hacer esto sería un Alcance personalizado que crea objetos nuevos cuando la configuración cambia. Desafortunadamente, ObjectFactory proporcionado al Alcance utiliza una definición de bean preprocesada, de modo que los marcadores de posición no se vuelvan a leer desde la configuración. Por lo tanto, los objetos creados tienen la misma configuración. :-(

+0

Probablemente una forma de hacerlo sería utilizar un PropertyOverrideConfigurer http://stackoverflow.com/a/595201/21499, pero creo que el mecanismo de anulación de propiedad es bastante incómodo de usar y propenso a errores. –

Respuesta

2

Lo siguiente es un poco extraño pero funciona. Crea un custom scope llamado reconfigurable que descarta todos los beans creados en ese ámbito cada vez que se produce una actualización de configuración. Por lo tanto, se creará un bean nuevo después de un cambio de configuración.

Los valores de configuración reales deben recuperarse mediante el lenguaje de expresiones de primavera, ya que los valores tanto para la sintaxis $ {} normal como para el PropertyOverrideConfigurer parecen estar fijados permanentemente en BeanDefinition. Una declaración de frijoles para un bean con una re-configurable propiedad someProperty se ve así:

<bean class="blablu.Testbean" scope="reconfigurable" 
    p:someProperty="#{ config['configexplicit']}"> 
    <aop:scoped-proxy /> 
</bean> 

Es necesario utilizar AOP: de ámbito proxy de tal manera que los granos que utilizan este bean siempre recuperar el grano más actualizado configurado desde el ámbito personalizado .

Declarar propiedades con @Value también funciona; si se utiliza la exploración componente tiene que declarar el alcance con la anotación

@Scope(value="reconfigurableScope", proxyMode=ScopedProxyMode.TARGET_CLASS) 

Si se preocupan por los detalles: la idea básica del ámbito de aplicación es:

public class ReconfigurableScope implements Scope { 

    private final Map<String, Object> nameToObjectMap = new ConcurrentHashMap<String, Object>(); 

    public Object get(final String name, final ObjectFactory<?> objectFactory) { 
     Object bean = nameToObjectMap.get(name); 
     if (null == bean) { 
      bean = objectFactory.getObject(); 
      nameToObjectMap.put(name, bean); 
     } 
     return bean; 
    } 

    // called from outside on each configuration change 
    public void update(final ConfigurationObservable observable, final Object arg) { 
     nameToObjectMap.clear(); 
    } 

} 

Plus algunas cosas hilo de seguridad y limpieza: los frijoles eliminados deben ser destruidos un poco más tarde y al cerrar el contexto de la aplicación.

+0

¿Se puede usar cualquier muestra de código fuente de su ámbito personalizado? :) – Kakawait

2

Desafortunadamente configuración de properties archivos es estática y ocurre normalmente en el arranque Lo que estoy haciendo es exponer atributos dinámicos a través de :.

@ManagedResource 
@Service 
public class BusinessService { 

    @ManagedAttribute 
    private int age; 

    public int getAge() { 
     return age; 
    } 

    public void setAge(int age) { 
     this.age = age; 
    } 

    public void businessMethod() { 
     //use age... 
    } 

} 

recuerde agregar:

<context:mbean-export/> 

Para su configuración. Ahora puede acceder y cambiar ese atributo a través del jconsole o cualquier otro cliente JMX. Vea también: 23.3.2 Using Source-Level Metadata (JDK 5.0 annotations).

+0

Los archivos de propiedades no son necesariamente estáticos: pueden residir en algún lugar del sistema de archivos y cambiarse por operaciones. Tiene razón: uno puede usar otros mecanismos para actualizar los valores de configuración, pero me gustaría usar el agradable mecanismo Spring placeholder. De lo contrario, ¿cómo actualizarías, digamos, un tiempo de espera para una WebserviceTemplate sin mucho código de pegamento? –

+0

@hstoerr: wrt 'WebserviceTemplate' - requiere un código de pegamento incluso cuando no necesita actualizar nada: http://onebyteatatime.wordpress.com/2009/03/19/how-to-set-socket-timeout -using-spring-webservicetemplate/y http://stackoverflow.com/questions/6733744 –

0

Para una reconfiguración de tiempo de ejecución efectiva, puede usar el proyecto Spring Config de la nube. En esta disposición, tendría un Configuration Repository, digamos un repositorio git, que contiene sus valores de configuración. Luego ponga un Configuration Server frente a ese repositorio. Este servidor se actualizaría siempre que ocurra un envío al repositorio de respaldo.Finalmente, sus aplicaciones serían clientes de ese Config Server y extraerán las nuevas configuraciones de él. Compruebe Spring Cloud para más detalles.

1

Hay un ejemplo de ejecución de lo que estamos tratando de lograr aquí: https://github.com/ldojo/spring-cloud-config-examples

Demuestra cómo un servidor de primavera de nubes Config y un servicio al cliente pueden comunicarse a través de la primavera Nube autobús, y las propiedades de configuración del cliente puede cambiar en tiempo de ejecución cuando hay un cambio de configuración en el repositorio del servidor de configuración.

Cuestiones relacionadas