【问题标题】:Spring Boot - Environment @Autowired throws NullPointerExceptionSpring Boot - 环境 @Autowired 抛出 NullPointerException
【发布时间】:2013-10-18 16:14:13
【问题描述】:

我有一个使用 Spring Boot 0.5.0.M5 的项目设置。

在其中一个配置文件中,我尝试使用@Autowire Environment,但使用NullPointerException 失败。

这是我目前所拥有的:

Application.java

@EnableAutoConfiguration
@Configuration
@ComponentScan
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

JpaConfig.java 我正在尝试@Autowire Environment

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.ui.persistence.repository")
public class JpaConfig {
    private static final String DATABASE_DRIVER = "db.driver";
    private static final String DATABASE_PASSWORD = "db.password";
    private static final String DATABASE_URL = "db.url";
    private static final String DATABASE_USERNAME = "db.username";
    private static final String HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    private static final String ENTITYMANAGER_PACKAGES_TO_SCAN 
        = "entitymanager.packages.to.scan";

    @Autowired
    private Environment env;

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty(DATABASE_DRIVER));
        dataSource.setUrl(env.getProperty(DATABASE_URL));
        dataSource.setUsername(env.getProperty(DATABASE_USERNAME));
        dataSource.setPassword(env.getProperty(DATABASE_PASSWORD));
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean 
                = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPersistenceProviderClass(
                HibernatePersistence.class);
        entityManagerFactoryBean.setPackagesToScan(
                env.getProperty(ENTITYMANAGER_PACKAGES_TO_SCAN));
        entityManagerFactoryBean.setJpaProperties(hibernateProperties());
        return entityManagerFactoryBean;
    }
}

我正在尝试加载在属性文件中配置的数据库属性。但是,Environment 未注入,代码失败并显示NullPointerException。我在 XML 文件中没有任何配置。

对于我这样配置PropertySourcesPlaceholderConfigurer的属性文件:

@Configuration
@PropertySource("classpath:database.properties")
public class PropertyConfig {
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

我尝试交换 @Autowired@Resource@Inject,但到目前为止没有任何效果。将不胜感激任何帮助。谢谢。

【问题讨论】:

  • 你能显示堆栈跟踪吗?另外,有什么提供Environment 的吗?我认为您需要一个类,该类的方法返回标有@Bean 的方法。此外,您也许可以使用@Value 来设置您的属性,而不是获取环境并以这种方式获取它们。
  • 我确实尝试了@Value,但没有奏效。堆栈跟踪只是 NullPointerException,因为尚未设置变量。谢谢。

标签: java spring-boot nullpointerexception autowired environment


【解决方案1】:

虽然您的具体问题已解决,以下是获取 Environment 的方法,以防 Spring 的自动装配发生得太晚

诀窍是实现org.springframework.context.EnvironmentAware;然后 Spring 将环境传递给 setEnvironment() 方法。 这从 Spring 3.1 开始有效。

一个例子:

@Configuration
@PropertySource("classpath:myProperties.properties")
public class MyConfiguration implements EnvironmentAware {

    private Environment environment;

    @Override
    public void setEnvironment(final Environment environment) {
        this.environment = environment;
    }

    public void myMethod() {
        final String myPropertyValue = environment.getProperty("myProperty");
        // ...
    }

}

这不像@Autowired@Value 那样优雅,但在某些情况下它可以作为解决方法。

【讨论】:

  • 我遇到了一个奇怪的情况,一个用 Configuration 注释的类有两个 Bean 方法。一种方法创建了一个 DataSource,另一种方法创建了一个 PropertySourcesPlaceholderConfigurer,我从我根据 Autowired Environment 字段中的值定位的属性文件初始化了它。效果很好(在初始化配置器之前初始化了环境)。我决定将属性方法与 Environment 字段一起移动到另一个类中,一旦我这样做了,在初始化配置器 bean 时 Environment 为空。使用 setEnvironment() 解决了这个问题。谢谢!
  • 注意:这意味着您的打印环境属性的run方法将在应用程序启动后执行。
【解决方案2】:

我相信 Spring 和 EntityManagerFactory 存在一些生命周期问题,你可能已经犯了这些问题(在 4.0.0.RC1 中修复) - 如果你的 @Configuration 类被超早实例化,它可能不会有资格进行自动装配。如果是这种情况,您可能可以从日志输出中看出。

只是出于兴趣,您是否知道,如果您使用@EnableAutoConfiguration,您的JpaConfigPropertyConfig 提供的功能已经预设为开箱即用(只要您@ComponentScan 您的存储库所在的那个包被定义)?有关示例,请参见 JPA sample in Spring Boot

【讨论】:

  • 它确实很早就被调用了,在这种情况下我需要编写代码来读取和设置属性吗?我确实看过它使用 hsqldb 的示例。我在 MySQL 上,我相信我需要为 DataSource 提供连接 URL、用户名等。感谢您抽出时间回复。
  • Spring Boot 有一些用于外部化DataSource 配置(example here)的约定,因此您无需执行任何操作。如果我是你,我会在你尝试 MySQL 之前让它与 H2 或 HSQLDB 一起工作。
  • 酷,像魅力一样工作(使用 MySQL)!谢谢戴夫!
【解决方案3】:

我在 Spring Batch 上遇到了同样的问题。编写器无法自动装配环境类,因为配置类是较早实例化的。 所以我创建了一种 Singleton(旧方式)来实例化 Environment,我每次都可以访问它。

我做了这个实现:

@Configuration
@PropertySource(value = { "classpath:kid-batch.properties" }, ignoreResourceNotFound = false)
public class BatchConfiguration implements EnvironmentAware {

private static Environment env;

public static String getProperty(String key) {
    return env.getProperty(key);
}

@Override
public void setEnvironment(Environment env) {
    BatchConfiguration.env = env;
}

}

它有效

【讨论】:

  • 这是我想说的最佳答案。非常感谢。
【解决方案4】:

我在从 Spring Boot 应用程序中的 application.properties 文件中读取属性时遇到了类似的问题。为了找出问题并使其发挥作用,我付出了很多努力。最后我完成了。这是我的常量类,它将从属性文件中读取属性值。我希望它会对某人有所帮助。

import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;

@Configuration
@PropertySource("classpath:application.properties")
public class Constants implements EnvironmentAware {

static Environment environment;

@Override
public void setEnvironment(Environment environment) {
    Constants.environment = environment;
}

@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
    return new PropertySourcesPlaceholderConfigurer();
}

public static String getActiveMQHost() {
    System.out.println(environment.getProperty("spring.activemq.broker-host"));
    return environment.getProperty("spring.activemq.broker-host");
}

public static String getActiveMQPort() {
    System.out.println(environment.getProperty("spring.activemq.broker-port"));
    return environment.getProperty("spring.activemq.broker-port");
}

public static String getActiveMQUser() {
    System.out.println(environment.getProperty("spring.activemq.user"));
    return environment.getProperty("spring.activemq.user");
}

public static String getActiveMQPassword() {
    System.out.println(environment.getProperty("spring.activemq.password"));
    return environment.getProperty("spring.activemq.password");
}

}

这些是在我的 application.properties 中声明的属性键,

spring.activemq.broker-host
spring.activemq.broker-port
spring.activemq.user
spring.activemq.password

【讨论】:

    猜你喜欢
    • 2018-11-12
    • 2014-12-10
    • 2017-06-06
    • 2018-07-15
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 2020-11-20
    相关资源
    最近更新 更多