Внедрить сервис весенней загрузки в неуправляемый класс - PullRequest
3 голосов
/ 03 апреля 2020

У меня есть набор классов, которые выходят из моего абстрактного класса ReportConfig. После создания они в настоящее время являются неизменяемыми и не управляются Spring.

Однако я обнаружил, что иногда мне нужно выполнить действие, которое требует использования определенного сервиса, но я изо всех сил пытаюсь найти лучший способ внедрить эти службы в мои неуправляемые экземпляры ReportConfig. Смотрите ниже:

@Service
public class ReportService() {

    @Autowired
    private SchemaService schemaService;

    @Autowired
    private ExecutionService executionService;

    @Autowired
    private ReportConfigFactory reportConfigFactory;

    public Result executeReport(ReportRequest request) {

        ReportConfig reportConfig = reportConfigFactory.getReportConfig(request);

        reportConfig.validateAgainstSchema(schemaService.getSchemaForDataset(reportConfig.getDataset()));

        executionService.execute(reportConfig.getQuery());

}

Теперь у меня нет проблем со строкой dataService.execute(), но у меня есть проблема со строкой reportConfig.validateAgainstSchema(), и я чувствую, что альтернативой будет что-то вроде:

reportConfig.validateAgainstSchema(schemaService);

Но я чувствую, что, возможно, представляет собой тесную связь.

Я предполагаю, что есть также способ внедрить SchemaService прямо в ReportConfigs, но не уверен, что это побеждает объект ...

Стремится услышать ваши мысли.

Спасибо

Ответы [ 5 ]

3 голосов
/ 08 апреля 2020

Из того, что я понял по текущему дизайну вашего приложения, о котором идет речь, и я предполагаю функциональность и думаю об альтернативном дизайне,

reportConfig.validateAgainstSchema(schemaService.getSchemaForDataset(reportConfig.getDataset()));

Что вы можете подумать, если reportconfig - это правильное место, чтобы сделать validateAgainstSchema, если не думать о его изменении. Является ли schemaService правильным местом для validateAgainstSchema (я думаю, что нет), если это также не подходящее место для этого, то создайте SchemaValidator или что-то подобное. Это то, о чем я мог бы подумать, используя информацию, которую вы мне дали.

Если validateAgainstSchema не отменяется никакими дочерними классами ReportConfig и возможность очень редка, то вам определенно следует подумать о ее перемещении. в другой класс. Причина, по которой я говорю это, заключается в том, что если схема меняется, вам не нужно менять reportConfig класс

Если она переопределена и существует несколько реализаций, то одним из способов будет использование фабрики валидатора для получения валидатор и сделать валидацию. Я даже не знаю, подходит ли это вашему варианту использования, но это все, что я могу предложить в вопросе. Надеюсь, это поможет вам в чем-то.

2 голосов
/ 07 апреля 2020

Почему вы должны внедрять сервисы в классы конфигурации? Не могли бы вы не передать, какой конфиг нужен напрямую?

В качестве альтернативы, если вам необходимо, вы можете использовать инъекцию, основанную на установщике, для автоматической передачи сервиса в абстрактный класс ReportConfig, или вы можете использовать инъекцию метода.

Что-то вроде

Setter based Injection

public abstract class ReportConfig {

   protected SchemaService schemaService;

   protected final setSchemaService(SchemaService schemaService) {
    this.schemaService = schemaService;
   }  

}

Method Injection

public class BeanUtility implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    protected SchemaService getSchemaService() {
        return this.applicationContext.getBean("schemaService", SchemaService.class);
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
0 голосов
/ 08 апреля 2020

Самое простое в вашем случае решение «также внедрить SchemaService прямо в ReportConfigs, но не уверен, что это побеждает объект ...» - это передать объект на фабрику.

Так что в принципе эта строка reportConfigFactory.getReportConfig(request); будет изменена на эту

reportConfigFactory.getReportConfig(request, schemaService);

Передача bean-компонента с пружинным управлением в конструкторе класса с неуправляемой пружиной вполне допустима. В вашем случае это не конструктор напрямую, а фабричный метод.

0 голосов
/ 08 апреля 2020

Можно подумать об упаковке ваших сервисов в классы c Держатель

public class SchemaServiceHolder {

   private static final SchemaServiceHolder INSTANCE = new SchemaServiceHolder();

   @Autowired
   private SchemaService schemaService;

   private SchemaServiceHolder () {
   }

   public static SchemaServiceHolder instance() {
      return INSTANCE;
   }

   public SchemaService getSchemaService() {
      return schemaService;
   }
}

Затем вам нужно создать бин этого типа, чтобы Spring мог внедрить сервис в синглтон SchemaServiceHolder.INSTANCE

@Configuration
public class AppConfig {
   @Bean
   public SchemaServiceHolder schemaServiceHolder () {
      return SchemaServiceHolder.instance();
   }
}

И, наконец, ваши объекты могут ссылаться на schemaService статически

SchemaService schemaService = SchemaServiceHolder.instance().getSchemaService();
0 голосов
/ 03 апреля 2020

Ваша логика немного странная. Правильным является другой сервис получения ReportConfig. Вы делаете обратное.

Вы можете работать с bean-компонентом внутри другого объекта, который не управляется пружиной, но вам нужно его воссоздать.

YourService container = (YourService) context.getBean("yourService");
container.load();

Но это неправильно. Правильный путь - это изменить свой логический. Создайте универсальный c сервис с правилами для указания c reportConfig. Автоматически подключите службу и передайте конфигурацию отчета и работайте с этими указанными c данными внутри службы. (извините, мой английский sh)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...