如何以编程方式解析Spring中的属性占位符

时间:2011-03-02 19:30:01

标签: spring jsp dependency-injection jsp-tags custom-tag

我目前正在使用基于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: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");

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

5 个答案:

答案 0 :(得分:35)

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

解决问题:

  1. 让您的课程实施EmbeddedValueResolverAware界面,您将获得为您解决的解析器

  2. 然后,您将能够检索代码段中演示的属性:

    String propertyValue = resolver.resolveStringValue("${your.property.name}");
    
  3. 然后你的bean不需要依赖ApplicationContext来检索你需要的属性。

答案 1 :(得分:23)

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

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

javadoc声明此方法用于解析嵌入值(例如注释属性),因此我们可能会绕过它的用法,但它可以正常工作。

答案 2 :(得分:15)

我认为不是专注于上下文占位符的内部工作,而是可以简单地定义一个新的util:这样的属性:

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

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

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

或者像这样,无论你在哪里做DI:

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

答案 3 :(得分:5)

一个选项是向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

答案 4 :(得分:1)

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