我目前正在基于Spring 3.1.0.M1的Web应用程序上工作,基于注释,并且在应用程序的一个特定位置解析属性占位符时遇到问题。
这里是故事。
1)在我的Web应用程序上下文中(由DispatcherServlet加载),我有
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)在app.properties中,有2个属性,其中包括:
app.properties:
# Properties provided (filtered) by Maven itself
app.version: 0.1-SNAPSHOT
...
# Static resources mapping
app.resources.path: resources/${app.version}
3)我的JSP 2.1模板中有一个JSP定制标记。该标签负责根据环境设置,应用程序版本,spring主题选择等来进行完整的资源路径构建。自定义标签类扩展了spring:url实现类,因此它可以被视为常用的url标签,但具有有关正确路径的一些附加知识。
我的问题是我无法在JSP定制标记实现中正确解析$ {app.resources.path}。 JSP自定义标签是由servlet容器而不是Spring管理的,因此不参与DI。所以我不能只使用通常的@Value(“ $ {app.resources.path}”)并由Spring自动解决它。
我所拥有的都是Web应用程序上下文实例,所以我必须以编程方式解析我的属性。
到目前为止,我尝试过:
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");
所以现在我有点坚持了。我知道解析占位符的能力就在上下文中,我只是不知道正确的方法。如有任何帮助或想法,我们将不胜感激。
我认为您不必像关注上下文占位符的内部工作,而是可以像这样简单地定义一个新的util:properties:
<util:properties id="appProperties" location="classpath:app.properties" />
并且在您的代码中,像这样使用它:
Properties props = appContext.getBean("appProperties", Properties.class);
或在任何可以做DI的地方都这样:
@Value("#{appProperties['app.resources.path']}")
自Spring 3.0.3起,存在EmbeddedValueResolverAware,其作用与另一篇使用appContext.getBeanFactory().resolveEmbeddedValue("${prop}")
调用的文章所提到的相同。
解决问题:
使您的类实现EmbeddedValueResolverAware接口,您将为您注入解析器
然后您将可以在其中检索代码片段中演示的属性:
String propertyValue = resolver.resolveStringValue("${your.property.name}");
然后,您的bean不需要依赖ApplicationContext来检索所需的属性。
从3.0版开始,Spring在beanFactory中保留了一个String解析器列表。您可以像这样使用它:
String value = appContext.getBeanFactory().resolveEmbeddedValue("${prop}");
javadoc将此方法声明为解决嵌入值,例如注释属性,因此也许我们正在绕过其用法,但它可以工作。
一种选择是在PropertySource
上添加MapPropertySource
(此处为ConfigurableEnvironment
以举例说明内存中的配置),并要求它为您解析属性。
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");
}
}
[可选地用Foo
注释@Configuration
类,以享受程序配置的强大功能,而偏向XML
。
还有另一种可能的解决方案:通过AspectJ使标记类@Configurable并启用编译时或加载时编织。然后,我可以在自定义标签中使用通常的Spring @Value批注。但是,实际上,我不想仅仅因为几个类而建立编织基础结构。仍在寻找通过ApplicationContext解析占位符的方法。
只需添加一个完整的答案,我就添加这个。
您可以使用这样的自定义类来做到这一点。
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.util.StringValueResolver;
import org.springframework.lang.Nullable;
public class MyValueResolver implements EmbeddedValueResolverAware {
@Nullable
private StringValueResolver embeddedValueResolver;
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}
public String readMyProperty(String propertyString){
return embeddedValueResolver.resolveStringValue(propertyString);
}
}
此propertyString
应作为"${my.property}"
传递。
鉴于.properties
文件中的它表示为
my.property=myPropertyValue