Spring 4.1x,SimpleNamingContextBuilder 和@Value("#{environment.xxx}")

Spring 4.1x, SimpleNamingContextBuilder and @Value("#{environment.xxx}")

到目前为止,我一直在使用 Spring 4.0.8,以下版本运行良好:

在我的单元测试中,我在 jndi 环境中设置了一个值:

SimpleNamingContextBuilder _simpleNamingContextBuilder =
        new SimpleNamingContextBuilder();
_simpleNamingContextBuilder.bind(
            "java:comp/env/myBoolVar", true);
_simpleNamingContextBuilder.activate();

然后在我的 class 中,我这样访问它:

@Value("#{environment.myBoolVar}")
private Boolean _myBoolVar = Boolean.FALSE;

我已经升级到 Spring 4.1.2,但它不再有效。始终使用默认值 false,因为 Spring 无法找到该值。

如果我使用方式访问这个值:

@Resource(mappedName = "java:comp/env/myBoolVar")

确实有效。

我一直在搜索 SO 和整个网络,我看到了大量的信息,但是 none 帮助我解决了这个问题。我的理解是 Spring 环境可以访问 @Value 所做的所有值。所以我不确定是什么问题。

仅供在此苦苦挣扎的任何人参考。最后,我把将 "myBoolVar" 值添加到 SimpleNamingContextBuilder 的代码放在一个带有 @BeforeClass 注释的方法中,现在它工作正常。

基本上发生的事情是,在启动时 Spring 试图在 StandardServletEnvironment.customizePropertySources() 方法中整理出它拥有的 PropertySources。当需要查找 jndiProperties 时,它会执行以下操作:

if(JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
        propertySources.addLast(new JndiPropertySource("jndiProperties"));
    }

该方法 JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable() 执行以下操作:

try {
            new InitialContext().getEnvironment();
            return true;
        }
        catch (Throwable ex) {
            return false;
        }

在我的例子中,对 getEnvironment() 的调用抛出了 NoInitialContextException:

javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial 

这阻止了 Spring 创建 jndiProperties PropertySource,因此我的布尔变量丢失了。

所以我开始在网上寻找发生这种情况的原因......但后来在 Spring 论坛上发现 old article 说这将我的代码放在 @BeforeClass 块中,等等瞧。

我希望这能在未来的某个时候为某人免去一些痛苦。