Spring Boot - Environment @Autowired抛出NullPointerException

时间:2021-05-18 23:22:09

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 Environment but that fails with a NullPointerException.

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

Here's what I have so far:

这是我目前所拥有的:

Application.java

Application.java

@EnableAutoConfiguration
@Configuration
@ComponentScan
public class Application {

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

JpaConfig.java where I am trying to @Autowire Environment

JpaConfig。我正在尝试使用@Autowire环境的java

@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 Environment is not injected and the code fails with NullPointerException. I do not have any configuration in XML files.

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

For the properties file I have configured PropertySourcesPlaceholderConfigurer this way:

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

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

I have tried swapping @Autowired, @Resource and @Inject but nothing has worked so far. Would appreciate any help. Thanks.

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

3 个解决方案

#1


4  

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 @Configuration class gets instantiated super early, it might not be eligible for autowiring. You can probably tell from the log output if that is the case.

我认为Spring和EntityManagerFactory存在一些生命周期问题,您可能遇到了这些问题(在4.0.0.RC1中得到了解决)——如果您的@Configuration类超早实例化,那么它可能不适合自动连接。如果是这样的话,您可能会从日志输出中得知。

Just out of interest, did you know that the functionality provided by your JpaConfig and PropertyConfig is already presetn out of the box if you use @EnableAutoConfiguration (as long as you @ComponentScan that package where your repositories are defined)? See the JPA sample in Spring Boot for an example.

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

#2


18  

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

尽管您的特定问题已经解决,但是这里介绍了如何获取环境,以防Spring的自动布线发生得太晚。

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

诀窍是实现org.springframe . context.environmental aware;然后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 @Autowire or @Value, but it works as workaround in some situations.

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

#3


1  

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上遇到了同样的问题。写入器不能自动连接环境类,因为配置类是先前实例化的。所以我创建了一种单例(旧方式)来实例化环境,我可以每次都访问它。

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

和它的工作原理

#1


4  

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 @Configuration class gets instantiated super early, it might not be eligible for autowiring. You can probably tell from the log output if that is the case.

我认为Spring和EntityManagerFactory存在一些生命周期问题,您可能遇到了这些问题(在4.0.0.RC1中得到了解决)——如果您的@Configuration类超早实例化,那么它可能不适合自动连接。如果是这样的话,您可能会从日志输出中得知。

Just out of interest, did you know that the functionality provided by your JpaConfig and PropertyConfig is already presetn out of the box if you use @EnableAutoConfiguration (as long as you @ComponentScan that package where your repositories are defined)? See the JPA sample in Spring Boot for an example.

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

#2


18  

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

尽管您的特定问题已经解决,但是这里介绍了如何获取环境,以防Spring的自动布线发生得太晚。

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

诀窍是实现org.springframe . context.environmental aware;然后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 @Autowire or @Value, but it works as workaround in some situations.

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

#3


1  

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上遇到了同样的问题。写入器不能自动连接环境类,因为配置类是先前实例化的。所以我创建了一种单例(旧方式)来实例化环境,我可以每次都访问它。

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

和它的工作原理