Как разместить метод фабрики @Bean в самом классе? - PullRequest
1 голос
/ 18 марта 2019

У меня есть класс, который должен содержать данные, которые десериализованы из файла JSON. Эти данные должны быть доступны в моем приложении, поэтому я хочу связать их как бин.

Чтобы сохранить логику десериализации и структуру данных вместе, я хотел поместить аннотированный фабричный метод @Bean в сам класс данных - вот так:

@Configuration
public class MyData {

    // factory method
    @Bean
    public static MyData loadMyData(ResourceLoader resourceLoader) throws IOException {
        try (InputStream input = resourceLoader.getResource("classpath:data.json").getInputStream()) {
            return new ObjectMapper().readValue(input, MyData.class);
        } 
    }

    // data structure
    private Map<String, DataDetail> details;

    // ...
}

Однако это не удалось, потому что @ComponentScan теперь находит два определения бина:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: нет доступного квалифицирующего компонента типа 'org.example.MyData': ожидается один соответствующий компонент, но найдено 2: myData, loadMyData

Я также пытался заменить @Configuration на @Component, но результат тот же.

Я просто пропускаю правильную аннотацию для класса или просто невозможно разместить метод @Bean в самом классе бинов?

Ответы [ 2 ]

0 голосов
/ 18 марта 2019

Как ответил Дэдпул, вы должны отделить класс MyData от класса @Configurtion.
@Configuration мета-аннотируется с помощью @Component, поэтому, когда вы аннотируете MyData с помощью @Configuration, Spring также связывает его как обычный bean-компонент, и это делает двойное определение bean-компонентов MyData.

0 голосов
/ 18 марта 2019

В основном я предпочитаю многоуровневую архитектуру с пружинной загрузкой, поэтому с двумя разными слоями для Configuration и model, например

пакет app.config

@Configuration
public class MyDataConfig {

// factory method
@Bean
public static MyData loadMyData(ResourceLoader resourceLoader) throws IOException {
    try (InputStream input = resourceLoader.getResource("classpath:data.json").getInputStream()) {
        return new ObjectMapper().readValue(input, MyData.class);
    } 
 }

}

пакет com.model

public class MyData {

// data structure
private Map<String, DataDetail> details;

    // ...
}
...