Spring 4.1.2升级后@Value("#{environment.xxx}")无法读取JNDI值求助
问题复现
你遇到的这个版本适配问题很典型——在Spring 4.0.8里,通过@Value("#{environment.myBoolVar}")能正常从JNDI环境获取绑定值,但升级到4.1.2后,这个变量就始终只能拿到默认的false,而旧的@Resource写法却不受影响。
再明确下你的场景细节:
- 单元测试中初始化JNDI绑定的代码:
SimpleNamingContextBuilder _simpleNamingContextBuilder = new SimpleNamingContextBuilder(); _simpleNamingContextBuilder.bind( "java:comp/env/myBoolVar", true); _simpleNamingContextBuilder.activate();
- 业务类中通过Environment取值的代码:
@Value("#{environment.myBoolVar}") private Boolean _myBoolVar = Boolean.FALSE;
问题根源
Spring 4.1版本对Environment的属性源机制做了关键调整:默认的StandardEnvironment不再自动注册JndiPropertySource。而在4.0.x版本中,这个JNDI属性源是默认包含在Environment的属性源列表里的,所以当时environment.myBoolVar能直接从JNDI中读取到值。
至于@Resource(mappedName = "java:comp/env/myBoolVar")能正常工作,是因为它是直接通过JNDI原生API进行查找,完全不依赖Environment的属性源体系,所以不受这次版本变化的影响。
两种可行的解决方案
方案1:手动给Environment添加JNDI属性源
你可以在单元测试的初始化逻辑里,把JndiPropertySource手动添加到当前的Environment中,让Environment能读取到JNDI绑定的值:
比如在单元测试的@Before方法里处理:
@Before public void setupJndiAndEnvironment() { // 初始化JNDI绑定 SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); builder.bind("java:comp/env/myBoolVar", true); builder.activate(); // 获取Spring上下文的Environment并添加JNDI属性源 ConfigurableEnvironment env = (ConfigurableEnvironment) applicationContext.getEnvironment(); env.getPropertySources().addLast(new JndiPropertySource("jndi")); }
或者用EnvironmentPostProcessor的方式,在配置类里全局添加:
@Configuration public class TestJndiConfig { @Bean public EnvironmentPostProcessor jndiPropertySourceProcessor() { return environment -> { if (environment instanceof ConfigurableEnvironment) { ConfigurableEnvironment configurableEnv = (ConfigurableEnvironment) environment; // 添加JNDI属性源到属性源列表的末尾 configurableEnv.getPropertySources().addLast(new JndiPropertySource("jndi")); } }; } }
方案2:修改@Value的SpEL表达式,直接读取JNDI
如果不想修改Environment的配置,也可以直接用SpEL的JNDI表达式来取值,绕过Environment的属性源机制,和@Resource的工作方式保持一致:
@Value("#{jndi['java:comp/env/myBoolVar']}") private Boolean _myBoolVar = Boolean.FALSE;
这种方式不需要额外的配置,直接通过Spring的JNDI表达式解析器获取绑定的值,在4.1.2版本中可以正常运行。
总结
核心差异就是Spring 4.1对Environment默认属性源的调整,导致原来依赖Environment读取JNDI的方式失效。上面两种方案都能解决问题,你可以根据自己的测试场景选择更合适的一种。
内容的提问来源于stack exchange,提问作者Robert Bowen

