Java Spring Boot - 环境 @Autowired 抛出 NullPointerException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19454289/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 17:20:19  来源:igfitidea点击:

Spring Boot - Environment @Autowired throws NullPointerException

javaspring-bootnullpointerexceptionautowiredenvironment

提问by imme

I have a project setup using Spring Boot 0.5.0.M5.

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

In one of the configuration files I am trying to @Autowire Environmentbut that fails with a NullPointerException.

在我尝试使用的配置文件之一中@Autowire Environment,失败并显示NullPointerException.

Here's what I have so far:

这是我到目前为止所拥有的:

Application.java

应用程序.java

@EnableAutoConfiguration
@Configuration
@ComponentScan
public class Application {

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

JpaConfig.javawhere I am trying to @Autowire Environment

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;
    }
}

I am trying to load the database properties configured in a properties file. However, the Environmentis not injected and the code fails with NullPointerException. I do not have any configuration in XML files.

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

For the properties file I have configured PropertySourcesPlaceholderConfigurerthis way:

对于我以PropertySourcesPlaceholderConfigurer这种方式配置的属性文件:

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

I have tried swapping @Autowired, @Resourceand @Injectbut nothing has worked so far. Would appreciate any help. Thanks.

我试图交换@Autowired@Resource并且@Inject但至今没有奏效。将不胜感激任何帮助。谢谢。

采纳答案by Dave Syer

I believe there were some lifecycle issues with Spring and the EntityManagerFactory, and you might have fallen foul of those (fixed in 4.0.0.RC1) - if your @Configurationclass gets instantiated super early, it might not be eligible for autowiring. You can probably tell from the log output if that is the case.

我相信,有同春和一些生命周期的问题EntityManagerFactory,你可能有那些(固定4.0.0.RC1)阵亡犯规-如果你的@Configuration类被超早期实例,它可能不符合自动装配。如果是这种情况,您可能可以从日志输出中判断出来。

Just out of interest, did you know that the functionality provided by your JpaConfigand PropertyConfigis already presetn out of the box if you use @EnableAutoConfiguration(as long as you @ComponentScanthat package where your repositories are defined)? See the JPA sample in Spring Bootfor an example.

只是出于兴趣,您是否知道您的JpaConfig和提供的功能PropertyConfig如果您使用@EnableAutoConfiguration(只要您@ComponentScan定义了存储库的那个包)就已经预先设置好了?有关示例,请参阅Spring Boot 中JPA 示例

回答by Alex Shesterov

Though your specific problem is solved, here's how to get Environmentin case Spring's autowiring happens too late.

尽管您的具体问题已解决,但这里是如何Environment解决Spring 的自动装配发生得太晚的方法

The trick is to implement org.springframework.context.EnvironmentAware; Spring then passes environment to setEnvironment()method. This works since Spring 3.1.

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

An example:

一个例子:

@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");
        // ...
    }

}

This is not as elegant as @Autowiredor @Value, but it works as workaround in some situations.

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

回答by Greg Florance

I had the same problem on Spring Batch. Writers cannot autowire Environment class because Configuration class was instantiated earlier. So I created a sort of Singleton (old manner) to instantiate Environment and I could access to it every time.

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

I did this implementation :

我做了这个实现:

@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;
}

}

}

And it works

它有效

回答by Nallamachu

I was having the similar issue to read properties from my application.properties file in spring boot application. I have struggled a lot to figure out the problem and make it work. Finally I have done. Here is my Constants class which will read properties values from properties file. I hope it will help to someone.

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

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");
}

}

These are the property key's declared in my application.properties,

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

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