Spring Boot - Environment @Autowired throws NullPointerException

У меня есть настройка проекта с помощью 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 но до сих пор ничего не работало. Поблагодарили бы за любую помощь. Благодарю.

Ответ 1

Я полагаю, что были некоторые проблемы жизненного цикла с Spring и EntityManagerFactory, и вы, возможно, ошиблись (исправлено в 4.0.0.RC1) - если ваш класс @Configuration будет @Configuration очень рано, он может не подходить для автоматического подключения. Вы можете, вероятно, сказать из вывода журнала, если это так.

Просто JpaConfig интереса, знаете ли вы, что функциональность, предоставляемая вашими JpaConfig и PropertyConfig, уже предустановлена, если вы используете @EnableAutoConfiguration (если вы @ComponentScan этот пакет, где определены ваши репозитории)? См. Пример JPA в Spring Boot для примера.

Ответ 2

Несмотря на то, что ваша конкретная проблема решена, здесь, как получить Environment в случае, если Spring электропроводка происходит слишком поздно.

Хитрость заключается в реализации org.springframework.context.EnvironmentAware; Затем Spring передает окружение setEnvironment(). Это работает с весны 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, но в некоторых ситуациях работает как обходной путь.

Ответ 3

У меня была такая же проблема в Spring Batch. Писатели не могут autwire класс среды, потому что ранее был создан экземпляр класса. Поэтому я создал своего рода синглтон (старая манера) для создания среды, и я мог бы получить к ней доступ каждый раз.

Я сделал эту реализацию:

@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

У меня возникла похожая проблема при чтении свойств из моего файла 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");
}

}

Это ключ свойства, объявленный в моем application.properties,

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