40

我目前正在开发一个基于 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 个属性,其中包括:

应用程序属性:

# 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 应用程序上下文实例,因此我必须以编程方式解析我的属性。

到目前为止,我尝试过:

资源标签.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");

所以现在我有点坚持。我知道解决占位符的能力是在上下文中的某个地方,我只是不知道正确的方法。
任何帮助或检查的想法都非常感谢。

4

6 回答 6

51

从 Spring 3.0.3 开始,就有 EmbeddedValueResolverAware,它的工作方式与另一篇使用appContext.getBeanFactory().resolveEmbeddedValue("${prop}")call 的帖子提到的方式相同。

解决问题:

  1. 让您的类实现 EmbeddedValueResolverAware 接口,您将为您注入解析器

  2. 然后,您将能够在其中检索属性,如代码片段中所示:

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

然后你的 bean 不需要依赖 ApplicationContext 来检索你需要的属性。

于 2013-04-19T14:15:11.960 回答
25

从 3.0 版开始,Spring 在 beanFactory 中保留了一个字符串解析器列表。你可以像这样使用它:

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

javadoc 声明此方法用于解析诸如注释属性之类的嵌入值,因此也许我们正在规避它的使用,但它确实有效。

于 2013-01-25T18:55:24.603 回答
15

我认为与其关注上下文占位符的内部工作,不如简单地定义一个新的 util:properties,如下所示:

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

在您的代码中,像这样使用它:

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

或者像这样在任何你可以做 DI 的地方:

@Value("#{appProperties['app.resources.path']}")
于 2011-03-03T01:15:42.270 回答
5

一种选择是向 a 添加一个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使用.@ConfigurationXML

于 2015-01-21T15:31:57.240 回答
1

还有另一种可能的解决方案:通过 AspectJ 使标记类 @Configurable 并启用编译时或加载时编织。然后,我可以在我的自定义标签中使用常见的 Spring @Value 注释。但是,真的,我不想仅仅因为几个类就设置编织基础设施。仍在寻找通过 ApplicationContext 解决占位符的方法。

于 2011-03-04T04:15:54.773 回答
0

只是为了添加一个完整的答案,我正在添加这个。

您可以使用这样的自定义类来做到这一点。

import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.util.StringValueResolver;
import org.springframework.lang.Nullable;

public class MyValueResolver implements EmbeddedValueResolverAware {
    //this will be injected using the setter injection.
    //Spring already has an implementation org.springframework.beans.factory.config.EmbeddedValueResolver
    //Or you can implement your own and use @Primary
    @Nullable
    private StringValueResolver resolver;

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.resolver = resolver;
    }

    public String readMyProperty(String propertyString){
        return resolver.resolveStringValue(propertyString);
    }
}

propertyString应该作为"${my.property}".

鉴于在.properties文件中它显示为

my.property=myPropertyValue
于 2020-01-20T08:15:20.930 回答