【问题标题】:@Value annotations inside my Java class don't load values from .properties file我的 Java 类中的 @Value 注释不会从 .properties 文件中加载值
【发布时间】:2013-09-30 03:36:39
【问题描述】:

在问这个问题之前,我尝试了以下类似的问题:

Injecting Properties using Spring & annotation @Value

How can I inject a property value into a Spring Bean which was configured using annotations?

Loading up properties file to a class in Spring

但是,就我而言,我没有使用任何 Web 应用程序或 Tomcat;我只是想通过 Spring 将 cluster.properties 文件加载到常规 Java 项目中,这样我就可以将虚拟数据摄取到 Accumulo 中。另外,我正在尝试从 cluster.properties 文件加载属性,而不是从 xml 文件中定义的键值对加载。

使用我从上面的链接中学到的知识和大量关于 Spring 的阅读,这就是我所拥有的:

我创建了以下 context.xml 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

      <!-- Define the Spring Bean to load our cluster properties -->
      <bean id="props" class="accumuloIngest.LoadProperties"></bean>

    </beans>  

这是我的 cluster.properties 文件的一个小 sn-p:

    cluster.instance=instance
    cluster.username=user

    etc...

接下来,我在 MainApp.java 类下创建了以下 Spring main 方法:

    package accumuloIngest;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class MainApp {

        // Spring main method used to load a cluster.properties file with the Spring framework
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml");
            LoadProperties myObj = LoadProperties.class.cast(ctx.getBean("props"));

            // Now print out the cluster.properties loaded by Spring to verify they aren't null
            StringBuffer springPropsBuffer = new StringBuffer();
            springPropsBuffer.append("Printing out cluster.properties read via Spring...");
            springPropsBuffer.append("\n\n");
            springPropsBuffer.append("instanceName= ");
            springPropsBuffer.append(myObj.getInstanceName());
            springPropsBuffer.append("\n");
            springPropsBuffer.append("userName= ");
            springPropsBuffer.append(myObj.getUserName());
            springPropsBuffer.append("\n");
            springPropsBuffer.append("password= ");
            springPropsBuffer.append(myObj.getPassword());
            springPropsBuffer.append("\n");
            springPropsBuffer.append("zooServers= ");
            springPropsBuffer.append(myObj.getZooServers());
            springPropsBuffer.append("\n");
            springPropsBuffer.append("tableName= ");
            springPropsBuffer.append(myObj.getTableName());
            springPropsBuffer.append("\n");
            springPropsBuffer.append("dataFile= ");
            springPropsBuffer.append(myObj.getDataFile());
            springPropsBuffer.append("\n");
            springPropsBuffer.append("dataDelim= ");
            springPropsBuffer.append(myObj.getDataDelim());
            springPropsBuffer.append("\n");
            springPropsBuffer.append("rowCount= ");
            springPropsBuffer.append(myObj.getRowCount());  
            springPropsBuffer.append("\n");
            System.out.println(springPropsBuffer.toString());

            // now start data ingest
            myObj.startIngest(); // method that calls Ingester class to start data ingest
        } // end of main method

    } // end of MainApp class

Spring 加载我的 context.xml 文件并加载我称为“props”的 Bean,但值仍然为空。看来我的 @Value 注释在我的 LoadProperties 类中不起作用:

    package accumuloIngest;
    import java.io.IOException;

    import org.apache.accumulo.core.client.AccumuloException;
    import org.apache.accumulo.core.client.AccumuloSecurityException;
    import org.apache.accumulo.core.client.TableExistsException;
    import org.apache.accumulo.core.client.TableNotFoundException;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
    import org.springframework.context.annotation.Bean;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;

    public class LoadProperties {

        // this class defines the Spring Bean and loads the cluster properties
        // using the SpringFramework

        @Bean
        public static PropertyPlaceholderConfigurer props(){
        PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
        Resource[] resource = new ClassPathResource[ ]
                { new ClassPathResource("/EclipseProjectName/src/cluster.properties") };
        ppc.setLocations(resource);
        ppc.setIgnoreUnresolvablePlaceholders(true);
        return ppc;
}

// Now load the properties from cluster.properties using the Spring Framework
private @Value("${cluster.instance}") String instanceName;
private @Value("${cluster.username}") String userName;
private @Value("${cluster.password}") String password;
private @Value("${cluster.zooServers}") String zooServers;
private @Value("${cluster.TableName}") String tableName;
private @Value("${cluster.DataFile}") String dataFile;
private @Value("${cluster.DataDelimiter}") String dataDelim;
private @Value("${cluster.rowCount}") int rowCount;

// Getters for the other Java classes to access properties loaded by Spring
public String getInstanceName() {
    return instanceName;
}
public String getUserName() {
    return userName;
}
public String getPassword() {
    return password;
}
public String getZooServers() {
    return zooServers;
}
public String getTableName() {
    return tableName;
}
public String getDataFile() {
    return dataFile;
}
public String getDataDelim() {
    return dataDelim;
}
public int getRowCount() {
    return rowCount;
}

        // method to kick off the ingest of dummy data
        void startIngest() {
            Ingester ingestObject = new Ingester();
            try {
                ingestObject.ingestData();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (TableNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (TableExistsException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (AccumuloException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (AccumuloSecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } // end of try-catch block
        } // end of startIngest method

    } // end of LoadProperties class

然而,当我在 Eclipse 中运行 MainApp.java 时,当我的 Ingester.java 类调用 getter 时,这些值为 null。

这是我在 Eclipse 中运行 MainApp.java 时的控制台输出:

    13/09/24 14:08:24 INFO support.ClassPathXmlApplicationContext: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@191f667c: startup date [Tue Sep 24 14:08:24 EDT 2013]; root of context hierarchy
    13/09/24 14:08:24 INFO xml.XmlBeanDefinitionReader: Loading XML bean definitions from class path resource [context.xml]
    13/09/24 14:08:24 INFO support.DefaultListableBeanFactory: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3cdd17f5: defining beans [props]; root of factory hierarchy
    Printing out cluster.properties read via Spring...

    instanceName= null
    userName= null
    password= null
    zooServers= null
    tableName= null
    dataFile= null
    dataDelim= null
    rowCount= 0

    Exception in thread "main" java.lang.IllegalArgumentException: argument was null:Is null- arg1? true arg2? true
        at org.apache.accumulo.core.util.ArgumentChecker.notNull(ArgumentChecker.java:36)
        at org.apache.accumulo.core.client.ZooKeeperInstance.<init>(ZooKeeperInstance.java:99)
        at org.apache.accumulo.core.client.ZooKeeperInstance.<init>(ZooKeeperInstance.java:85)
        at accumuloIngest.Ingester.ingestData(Ingester.java:65)
        at accumuloIngest.LoadProperties.startIngest(LoadProperties.java:69)
        at accumuloIngest.MainApp.main(MainApp.java:44)

我是否缺少在我的 cluster.properties 文件中加载属性的 Spring 框架的一部分?我曾尝试将 @AutoWired 添加到我的 MainApp 和 LoadProperties java 类中,但这似乎没有帮助。

【问题讨论】:

  • 这里有很多问题。首先,为什么在使用 3.0 中引入的 @Bean 时,您的上下文命名空间会声明 Spring bean 版本 2.0?
  • 是的,这是我的复制/粘贴错误。我在 pom.xml 中定义了 Spring Framework 3.2.4,所以我修改了我的 context.xml 以使用 Spring beans 3.2 版

标签: java spring properties annotations accumulo


【解决方案1】:

如果您要使用@Bean,则需要@Configuration。您不应声明 xml 上下文以包含注释上下文。您也不应该将 @Configuration 类实例用作 bean。 ClassPathXmlApplicationContext 不适合处理基于注解的配置。

使用类似下面的东西

@Configuration
@ComponentScan(basePackageClasses = LoadProperties.class)
public static class Config {
    @Bean
    public static PropertyPlaceholderConfigurer props() {
        PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
        Resource[] resource = new ClassPathResource[] { new ClassPathResource(
                "/EclipseProjectName/src/cluster.properties") };
        ppc.setLocations(resource);
        ppc.setIgnoreUnresolvablePlaceholders(true);
        return ppc;
    }  

    @Bean
    public LoadProperties loadProperties() {
        return new LoadProperties();
    }
}

public static class LoadProperties {
    private @Value("${cluster.zooServers}") String zooServers;
    ... // getters and setters
}

public static void main(String[] args) throws Exception {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
    LoadProperties load = (LoadProperties) context.getBean(LoadProperties.class);
    System.out.println(load.getZooServers());
}

需要注意的几点:

  1. 在您的ClassPathResource 中,您需要指定一个类路径资源。你的类路径的根目录下真的有资源/EclipseProjectName/src/cluster.properties 吗?我非常怀疑。
  2. 在这种情况下,您不需要@ComponentScan,但请熟悉它。
  3. PropertyPlaceholderConfigurer 需要声明为静态,以便可以在其他 @Bean 声明之前对其进行初始化。您应该将PropertySourcesPlaceholderConfigurer 用作explained in the javadoc

【讨论】:

  • 是的,你是对的,我的类路径的根目录下没有资源。我阅读了谈论 ClassPathResource 的 Spring API,即docs.spring.io/spring/docs/3.2.4.RELEASE/javadoc-api,并意识到我应该在上面指定一个 java 类。但是如何确定要指定哪个 ClassPathResource?
  • @user2160928 这里我假设你想要一个.properties 文件,所以指定它的路径。您需要弄清楚您的程序是如何编译和构建的,以弄清楚该路径是什么或应该是什么。
  • 好的,所以我所拥有的是正确的。我的 cluster.properties 文件位于我的 Eclipse 项目(我在上面称为 EclipseProjectName)下的 src 目录下
  • @user2160928 它可能在您的文件系统中,但 eclipse 在 bin 文件夹中构建您的应用程序 (afaik)。另外,如果你从war 文件中运行它,你认为它会在哪里?
  • 我进入了我的 Eclipse 项目的 Properties 菜单,在 Java Build Path 下,它在我的构建路径中包含了 Source 文件夹 /src。另外,我尝试了您上面建议的代码更改,但似乎找不到我的 cluster.properties 文件。
猜你喜欢
  • 2019-03-14
  • 2012-09-26
  • 2015-03-13
  • 2013-04-02
  • 2016-08-09
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 1970-01-01
相关资源
最近更新 更多