Свойство файл загрузки проекта с несколькими модулями Spring-Boot

У меня есть Spring-Boot-Application как мультимодуль-проект в maven. Структура выглядит следующим образом:

Parent-Project
|--MainApplication
|--Module1
|--ModuleN

В проекте MainApplication имеется класс метода main() аннотированный с помощью @SpringBootApplication и т.д. Этот проект имеет, как всегда, файл application.properties, который загружается автоматически. Поэтому я могу получить доступ к значениям с @Value аннотации @Value

@Value("${myapp.api-key}")
private String apiKey;

В моем Module1 я также хочу использовать файл свойств (называемый module1.properties), где хранится конфигурация модулей. Этот файл будет доступен и доступен только в этом модуле. Но я не могу загрузить его. Я попробовал это с @Configuration и @PropertySource но не повезло.

@Configuration
@PropertySource(value = "classpath:module1.properties")
public class ConfigClass {

Как загрузить файл свойств с помощью Spring-Boot и легко получить доступ к этим значениям? Не удалось найти правильное решение.

Моя конфигурация

@Configuration
@PropertySource(value = "classpath:tmdb.properties")
public class TMDbConfig {

    @Value("${moviedb.tmdb.api-key}")
    private String apiKey;

    public String getApiKey() {
        return apiKey;
    }

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

Вызов конфигурации

@Component
public class TMDbWarper {

@Autowired
private TMDbConfig tmdbConfig;

private TmdbApi tmdbApi;

public TMDbWarper(){
    tmdbApi = new TmdbApi(tmdbConfig.getApiKey());
}

Я получаю исключение NullPointerException в конструкторе, когда я autowire warper.

Ответы

Ответ 1

Autowiring выполняется сразу после создания объекта (после вызова конструктора посредством отражения). Таким образом, NullPointerException ожидается в вашем конструкторе, поскольку поле tmdbConfig будет null при вызове конструктора

Вы можете исправить это, используя метод обратного вызова @PostConstruct, как показано ниже:

@Component
public class TMDbWarper {

    @Autowired
    private TMDbConfig tmdbConfig;

    private TmdbApi tmdbApi;

    public TMDbWarper() {

    }

    @PostConstruct
    public void init() {
        tmdbApi = new TmdbApi(tmdbConfig.getApiKey());
    }

    public TmdbApi getTmdbApi() {
        return this.tmdbApi;
    }
}

Остальная конфигурация кажется мне верной.

Надеюсь это поможет.

Ответ 2

Для полевого впрыска:

Поля вводятся сразу после построения компонента, прежде чем вызывать любые методы конфигурации. Такое поле конфигурации не должно быть общедоступным. Обратитесь к автообновленной аннотации для полного использования. Используйте инъекцию конструктора в этом случае, как показано ниже:

@Component
public class TMDbWarper {

    private TMDbConfig tmdbConfig;

    private TmdbApi tmdbApi;

    @Autowired
    public TMDbWarper(final TMDbConfig tmdbConfig){
            this.tmdbConfig = tmdbConfig;
            tmdbApi = new TmdbApi(tmdbConfig.getApiKey());
    }

(или же)

Используйте @PostConstruct для инициализации, как @PostConstruct ниже:

@Component
public class TMDbWarper {

    @Autowired
    private TMDbConfig tmdbConfig;

    private TmdbApi tmdbApi;

    @PostConstruct
    public void init() {
        // any initialisation method
        tmdbConfig.getConfig();
    }

Ответ 3

Вот пример мультимодуля Spring Boot, в котором вы можете получить свойства в другом модуле. Скажем, у меня есть основной модуль приложения, dataparse-module, datasave-module.

StartApp.java в прикладном модуле:

@SpringBootApplication
public class StartApp {

    public static void main(String[] args) {

        SpringApplication.run(StartApp.class, args);
    }
}

Конфигурация в datararse-модуле. ParseConfig.java:

@Configuration
public class ParseConfig {
        @Bean
        public XmlParseService xmlParseService() {
            return new XmlParseService();
        }
}

XmlParseService.java:

@Service
public class XmlParseService {...}

Конфигурация в datasave-модуле. SaveConfig.java:

@Configuration
@EnableConfigurationProperties(ServiceProperties.class)
@Import(ParseConfig.class)//get beans from dataparse-module - in this case XmlParseService
public class SaveConfig {

    @Bean
    public SaveXmlService saveXmlService() {
        return new SaveXmlService();

    }

}

ServiceProperties.java:

@ConfigurationProperties("datasave")
public class ServiceProperties {

    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

application.properties в datasave-модуле в папке resource/config:

datasave.message = Многомодульный проект Maven!

threads.xml.number = 5

file.location.on.disk = D:\Temp\реестра

Затем в модуле datasave вы можете использовать все свои свойства либо через @Value.

SaveXmlService.java:

@Service
public class SaveXmlService {

    @Autowired
    XmlParseService xmlParseService;

    @Value("${file.location.on.disk: none}")
    private String fileLocation;

    @Value("${threads.xml.number: 3}")
    private int numberOfXmlThreads;

    ...
}

Или через ServiceProperties:

Service.java:

@Component
public class Service {

    @Autowired
    ServiceProperties serviceProperties;

    public String message() {

        return serviceProperties.getMessage();

    }
}

Ответ 4

Раньше у меня была эта ситуация, я заметил, что файл свойств не был скопирован в банку.

Я сделал следующее, чтобы заставить его работать:

  1. В папке ресурсов я создал уникальный пакет, а затем сохранил в нем файл application.properties. например: com/компания/проект

  2. В файле конфигурации, например: TMDBConfig.java, я указал полный путь к файлу.properties:

    @Configuration
    @PropertySource("classpath:/com/company/project/application.properties")
    public class AwsConfig
    

Постройте и запустите, он будет работать как магия.

Ответ 5

Вы можете использовать autwire и использовать компонент Enviornment для чтения свойства

@Configuration
@PropertySource(value = "classpath:tmdb.properties")
public class TMDbConfig {

  @Autowired
  private Environment env;

  public String getApiKey() {
    return env.getRequiredProperty("moviedb.tmdb.api-key");
  }

}

Это должно гарантировать, что свойство считывается из контекста при вызове getApiKey() независимо от того, когда выражение @Value разрешено PropertySourcesPlaceholderConfigurer.