example - spring mvc que es
Cómo resolver mediante programación el marcador de posición de propiedad en Spring (5)
Creo que en lugar de centrarse en el funcionamiento interno del contenedor de contexto, simplemente puede definir una nueva utilidad: propiedades como esta:
<util:properties id="appProperties" location="classpath:app.properties" />
y en tu código, úsalo así:
Properties props = appContext.getBean("appProperties", Properties.class);
O como este donde sea que puedas hacer DI:
@Value("#{appProperties[''app.resources.path'']}")
Actualmente trabajo en una aplicación web basada en Spring 3.1.0.M1, basada en anotaciones, y tengo un problema para resolver los marcadores de posición de propiedad en un lugar específico de mi aplicación.
Aquí está la historia.
1) En mi contexto de aplicación 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) Inside app.properties, hay 2 propiedades, entre otras:
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 mis plantillas JSP 2.1. 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 resolver $ {app.resources.path} 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 probé:
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 atrapado 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.
Desde Spring 3.0.3 hay EmbeddedValueResolverAware que funcionará de la misma manera que lo mencionó otra publicación que usa la appContext.getBeanFactory().resolveEmbeddedValue("${prop}")
.
Para resolver el problema:
Haga que su clase implemente la interfaz EmbeddedValueResolverAware y obtendrá la solución de resolución para usted
Luego, donde podrá recuperar las propiedades como se muestra en un fragmento de código:
String propertyValue = resolver.resolveStringValue("${your.property.name}");
Entonces su bean no necesita depender de ApplicationContext para recuperar las propiedades que necesita.
Desde la versión 3.0, Spring mantiene una lista de resolución de cadenas en beanFactory. Puedes usarlo así:
String value = appContext.getBeanFactory().resolveEmbeddedValue("${prop}");
El javadoc establece este método en cuanto a la resolución de valores incrustados, como los atributos de anotación, así que tal vez estamos eludiendo su uso, pero funciona.
Hay una solución más posible: crear clases de etiquetas @Configurable a través de AspectJ y habilitar 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.
Una opción es agregar un PropertySource
(aquí MapPropertySource
para ejemplificar una configuración en memoria) a un MapPropertySource
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");
}
}
Opcionalmente anote la clase Foo
con @Configuration
para disfrutar del poder de la configuración programática a favor de XML
.