Spring 为什么可以';t@Value从环境中注入JNDI值?

Spring 为什么可以';t@Value从环境中注入JNDI值?,spring,tomcat,jndi,Spring,Tomcat,Jndi,我在使用@Value注释将Tomcat中的JNDI值注入SpringJava配置时遇到了问题,而通过类检索这些值却没有问题。我们正在使用Java1.7.0_17、Spring4.0.3和Tomcat7.0.52 我在context.xml中定义了以下变量: 在我的Java配置文件中,我有以下代码运行: @Bean public Foo foo( Environment env ){ return new Foo( env.getProperty("USER_NAME"), env.g

我在使用
@Value
注释将Tomcat中的JNDI值注入SpringJava配置时遇到了问题,而通过类检索这些值却没有问题。我们正在使用Java1.7.0_17、Spring4.0.3和Tomcat7.0.52

我在
context.xml中定义了以下变量:


在我的Java配置文件中,我有以下代码运行:

@Bean
public Foo foo( Environment env ){
    return new Foo( env.getProperty("USER_NAME"), env.getProperty("USER_PASSWORD") );
}
当我查看服务器日志时,我看到:

12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.c.e.PropertySourcesPropertyResolver -> Searching for key 'USER_NAME' in [servletConfigInitParams]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.c.e.PropertySourcesPropertyResolver -> Searching for key 'USER_NAME' in [servletContextInitParams]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.c.e.PropertySourcesPropertyResolver -> Searching for key 'USER_NAME' in [jndiProperties]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.springframework.jndi.JndiTemplate -> Looking up JNDI object with name [java:comp/env/USER_NAME]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.jndi.JndiLocatorDelegate -> Located object with JNDI name [java:comp/env/USER_NAME]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.jndi.JndiPropertySource -> JNDI lookup for name [USER_NAME] returned: [initech]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.c.e.PropertySourcesPropertyResolver -> Found key 'USER_NAME' in [jndiProperties] with type [String] and value 'initech'
但是,如果可能的话,我想使用
@Value
注释使代码更干净;类似于

@Bean
public Foo foo(
        @Value( "#{USER_NAME}" ) String userName,
        @Value( "#{USER_PASSWORD}" ) String userPassword
    ){

    return new Foo( userName, userPassword );
}
但此代码会导致错误:

nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'USER_NAME' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'USER_NAME' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'oauthTokenRequestClient' defined in class path resource [com/initech/set/gw/api/config/GatewayRepositoryConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.net.URI]: : Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'USER_NAME' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'USER_NAME' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?
org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)
我也尝试过
“{systemEnvironment.USER_NAME}
”{systemProperties.USER_NAME}
“{jndproperties.USER_NAME}
”{java:comp/env/USER_NAME}
,但它们都不起作用


PS-我试图简化这个问题,因此如果其中一个应该有效,请让我知道,因为我可能在发布中出错。

如果您使用的是Spring 4,您应该更改

  @Value( "#{USER_PASSWORD}" ) String userPassword

试一试,看看会发生什么。

我用这个问题的答案解决了它

所以我的代码看起来像:

@Bean
public Foo foo(
        @Value( "#{environment.USER_NAME}" ) String userName,
        @Value( "#{environment.USER_PASSWORD}" ) String userPassword
    ){

    return new Foo( userName, userPassword );
}

我假设从(即“假设您有一个
属性资源占位符配置器
已注册”)的内容到该问题,这意味着我们缺少一个已配置的
属性资源占位符配置器

这是正确的语法

  @Value("${PASSWORD}")
看看这个例子:

对于Spring 3.1+(在4.2.5版本中测试),您可以像这样使用
@Value

@Value("${property.name}")
private String jndiProperty;
但是您还需要在
静态
方法中定义
属性资源占位符配置器
bean,并配置
jndPropertySource
(我在
@Configuration
类中有此功能):


注意
addFirst()
的使用,它确保JNDI的属性值在与其他属性源发生冲突时优先,这可能是需要的,也可能不是需要的,在这种情况下,可以使用其他方法,如
addLast()
等。

可能重复@Morfic是的,它几乎是。我一定错过了,因为我在搜索“JNDI”而不是“环境”。如果这个问题不被删除的话,将来对像我这样的人仍然会有帮助。
@Value(“{environment.USER\u NAME}”)
对我有效,而
@Value(${USER\u NAME}”)
对我无效。我实际使用的类型是
URI
,使用
@Value(${USER\u NAME}”)
时,我从
URI
构造函数中得到一个异常,“$”是一个无效字符,这表明它在使用
$
时使用了文本值
占位符您必须注册
属性资源占位符配置器
,否则它将无法工作。此注册必须使用带有
@Bean
注释的
公共静态
方法完成。请参阅此问题的公认答案,但它不是来自属性文件,而是来自容器的
context.xml
中的JNDI值,我已经尝试过了,但没有成功。
@Value("${property.name}")
private String jndiProperty;
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(ConfigurableEnvironment env) {
    PropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer();

    JndiPropertySource jndiPropertySource = new JndiPropertySource("java:comp");
    env.getPropertySources().addFirst(jndiPropertySource);

    return placeholderConfigurer;
}