2011-03-02 14 views
31

Actualmente trabajo en una aplicación web basada en Spring 3.1.0.M1, basada en anotaciones, y tengo un problema para resolver marcadores de posición de propiedad en un lugar específico de mi aplicación.Cómo resolver mediante programación el marcador de posición de propiedad en Spring

Aquí está la historia.

1) En mi contexto de aplicaciones web (cargado por DispatcherServlet), tengo

mvc-config.xml:

<!-- Handles HTTP GET requests for /resources/version/** --> 
<resources mapping="/${app.resources.path}/**" location="/static/" cache-period="31556926"/> 

... 

<!-- Web properties --> 
<context:property-placeholder location=" 
    classpath:app.properties 
    "/> 

2) Dentro de app.properties, hay 2 propiedades, entre otros :

app.properties:

# Properties provided (filtered) by Maven itself 
app.version: 0.1-SNAPSHOT 
... 

# Static resources mapping 
app.resources.path: resources/${app.version} 

3) tengo una etiqueta personalizada JSP en mi JS P 2.1 plantillas. Esta etiqueta es responsable de la construcción completa de rutas de recursos dependiendo de la configuración del entorno, la versión de la aplicación, la selección del tema de primavera, etc. La clase de etiqueta personalizada extiende la clase de implementación de spring: url, por lo que puede considerarse una etiqueta url habitual pero con algunos conocimientos adicionales.

Mi problema es que no puedo obtener $ {app.resources.path} resuelto correctamente en la implementación de mi etiqueta personalizada JSP. Las etiquetas personalizadas de JSP son administradas por el contenedor de servlets, no por Spring, y por lo tanto no participan en DI. Así que no puedo usar el @Value habitual ("$ {app.resources.path}") y Spring lo resuelve automáticamente.

Todo lo que tengo allí es la instancia de contexto de la aplicación web, así que tengo que resolver mi propiedad mediante programación.

Hasta ahora he intentado:

ResourceTag.java:

// returns null 
PropertyResolver resolver = getRequestContext().getWebApplicationContext().getBean(PropertyResolver.class); 
resolver.getProperty("app.resources.path"); 


// returns null, its the same web context instance (as expected) 
PropertyResolver resolver2 = WebApplicationContextUtils.getRequiredWebApplicationContext(pageContext.getServletContext()).getBean(PropertyResolver.class); 
resolver2.getProperty("app.resources.path"); 


// throws NPE, resolver3 is null as StringValueResolver is not bound 
StringValueResolver resolver3 = getRequestContext().getWebApplicationContext().getBean(StringValueResolver.class); 
resolver3.resolveStringValue("app.resources.path"); 


// null, since context: property-placeholder does not register itself as PropertySource 
Environment env = getRequestContext().getWebApplicationContext().getEnvironment(); 
env.getProperty("app.resources.path"); 

Así que ahora estoy un poco atascado con eso. Sé que la capacidad de resolver mi marcador de posición está en algún lugar del contexto, simplemente no sé la forma correcta de hacerlo.
Cualquier ayuda o ideas para verificar son muy apreciadas.

Respuesta

13

Creo que en lugar de centrarse en el funcionamiento interno de lugar contexto titular, sólo tiene que definir un nuevo util: propiedades de esta manera:

<util:properties id="appProperties" location="classpath:app.properties" /> 

y en su código, utilizar de esta manera:

Properties props = appContext.getBean("appProperties", Properties.class); 

O como esto dondequiera que usted puede hacer DI:

@Value("#{appProperties['app.resources.path']}") 
+0

Gracias, Ritesh. Creo que puedo usar esta solución, en caso de que no se encuentre nada más elegante. –

+0

Marcó esta respuesta como Aceptada, pero de todos modos es interesante encontrar una solución puramente programática. –

+0

@Max Alexejev También puede extender PropertyPlaceholderConfigurer y capturar propiedades resueltos que se pasan en el segundo argumento al método processProperties. Pero luego tendrá que usar la configuración de bean en lugar de context: property-placeholder. – Ritesh

1

Hay otra posible solución: hacer clas etiqueta ses @Configurable a través de AspectJ y habilita el entrelazado en tiempo de compilación o tiempo de carga. Entonces, podría usar las anotaciones Spring @Value habituales en mis etiquetas personalizadas. Pero, realmente, no quiero configurar infraestructura de tejido solo por un par de clases. Sigue buscando una forma de resolver el marcador de posición mediante ApplicationContext.

23

Desde la versión 3.0, Spring mantiene una lista de resolución de cadenas en beanFactory. Se puede utilizar la siguiente manera:

String value = appContext.getBeanFactory().resolveEmbeddedValue("${prop}"); 

Los estados javadoc este método que para resolver valores implícitos tales como atributos de anotación así que tal vez están eludiendo su uso, pero funciona.

+0

¡Muchas gracias! Estaba buscando un tiempo ahora para una forma limpia de consultar el entorno. –

30

desde la primavera 3.0.3 hay EmbeddedValueResolverAware que trabajará misma manera como se ha mencionado por otro post que utiliza appContext.getBeanFactory().resolveEmbeddedValue("${prop}") llamada.

para resolver el problema:

  1. Haga su clase para implementar la interfaz EmbeddedValueResolverAware y obtendrá resolver inyectado para que

  2. A continuación, en la que será capaz de recuperar las propiedades como se ha demostrado en un código fragmento:

    String propertyValue = resolver.resolveStringValue("${your.property.name}"); 
    

Luego, su be y no necesita depender de ApplicationContext para recuperar las propiedades que necesita.

+3

Esta es una forma muy simple de resolver el problema. Para cualquier futuros lectores, sólo tiene que añadir el EmbeddedValueResolverAware interfaz de la clase primavera gestionados en el que desea ser capaz de resolver propiedades mediante programación, poner en práctica el método de selección, y el uso de los códigos @Eds escribieron para resolver. – Alex

+0

De hecho, Alex merece el visto bueno por su comentario. ¿No quieres editar la respuesta? – Heri

+0

Este es el único enfoque que he visto que parece aceptable para escribir componentes compartidos/config que tienen que trabajar para múltiples aplicaciones de primavera. No desea que dicho código dependa de cómo una aplicación determinada obtiene su configuración de propiedad de archivos u otros medios. –

4

Una opción es agregar un PropertySource (aquí MapPropertySource para ejemplificar una configuración en memoria) a un ConfigurableEnvironment y pedirle que resuelva las propiedades por usted.

public class Foo { 

    @Autowired 
    private ConfigurableEnvironment env; 

    @PostConstruct 
    public void setup() { 
     env.getPropertySources() 
      .addFirst(new MapPropertySource("my-propertysource", 
       ImmutableMap.<String, Object>of("your.property.name", "the value"))); 
     env.resolvePlaceholders("your.property.name"); 
    } 
} 

Anotar Opcionalmente la clase Foo con @Configuration a disfrutar de la potencia de la configuración programática en favor de XML.

Cuestiones relacionadas