You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring中JndiTemplate无法从yaml配置获取jms.java.naming.provider.url值

Why ${jms.java.naming.provider.url} Isn't Resolving from application.yaml

I've run into this exact issue before with XML-based Spring configurations and YAML property files. Let's break down the root causes and walk through actionable fixes:

Common Causes

1. Bean Initialization Order Mismatch

Your jndiTemplate bean is likely being initialized before the yamlProperties bean and context:property-placeholder have finished loading and processing the YAML file. Spring doesn't guarantee initialization order in XML unless explicitly specified, so the placeholder ${jms.java.naming.provider.url} tries to resolve before the property source is ready.

2. Limited YAML Support in context:property-placeholder

Older versions of Spring's <context:property-placeholder> have quirks when working with YamlPropertiesFactoryBean. While it can technically work, the XML namespace doesn't handle YAML-specific edge cases (like nested properties) as reliably as modern Java config or Spring Boot's native support.

3. Typos or Invalid YAML Structure

Double-check your application.yaml to ensure the property is correctly formatted (no indentation errors, proper nesting):

jms:
  java:
    naming:
      provider:
        url: tcp://your-jms-server:61616

Fixes to Try

Method 1: Enforce Bean Order in XML

Add depends-on to your jndiTemplate bean to ensure it waits for yamlProperties to load, and update the placeholder config to ignore unresolvable values temporarily:

<bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
  <property name="resources" value="classpath:application.yaml"/>
</bean>

<context:property-placeholder properties-ref="yamlProperties" ignore-unresolvable="true"/>

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate" depends-on="yamlProperties">
  <property name="environment">
    <props>
      <prop key="java.naming.factory.initial">string-works</prop>
      <prop key="java.naming.provider.url">${jms.java.naming.provider.url}</prop>
    </props>
  </property>
</bean>

Java config gives you full control over initialization order and avoids XML namespace limitations. Here's a clean rewrite:

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jndi.JndiTemplate;
import java.util.Properties;

@Configuration
public class JmsConfig {

    // Load YAML first (static bean ensures early initialization)
    @Bean
    public static YamlPropertiesFactoryBean yamlProperties() {
        YamlPropertiesFactoryBean factoryBean = new YamlPropertiesFactoryBean();
        factoryBean.setResources(new ClassPathResource("application.yaml"));
        return factoryBean;
    }

    // Configure placeholder resolver with YAML properties
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        configurer.setProperties(yamlProperties().getObject());
        return configurer;
    }

    // Create JndiTemplate with resolved properties
    @Bean
    public JndiTemplate jndiTemplate() {
        JndiTemplate template = new JndiTemplate();
        Properties env = new Properties();
        env.put("java.naming.factory.initial", "string-works");
        env.put("java.naming.provider.url", "${jms.java.naming.provider.url}");
        template.setEnvironment(env);
        return template;
    }
}

Method 3: Simplify with Spring Boot (If Applicable)

If you're using Spring Boot, you don't need manual YAML loading at all. Use @ConfigurationProperties to bind properties cleanly:

  1. Add the configuration processor dependency (if missing):
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
  1. Create a properties binding class:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "jms.java.naming.provider")
public class JmsProviderProperties {
    private String url;

    // Getter and Setter
    public String getUrl() { return url; }
    public void setUrl(String url) { this.url = url; }
}
  1. Inject properties into your JndiTemplate bean:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jndi.JndiTemplate;
import java.util.Properties;

@Configuration
public class JmsConfig {

    @Bean
    public JndiTemplate jndiTemplate(JmsProviderProperties properties) {
        JndiTemplate template = new JndiTemplate();
        Properties env = new Properties();
        env.put("java.naming.factory.initial", "string-works");
        env.put("java.naming.provider.url", properties.getUrl());
        template.setEnvironment(env);
        return template;
    }
}

Debugging Tip

Enable Spring's debug logging for the org.springframework.core.env package. This will show you exactly which properties are loaded and whether your ${jms.java.naming.provider.url} is being resolved correctly during bean initialization.

内容的提问来源于stack exchange,提问作者Bojja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:48:55