Как динамически определить класс обслуживания для использования во время выполнения - PullRequest
0 голосов
/ 07 июня 2019

Для некоторого контекста у меня есть Java-приложение, которое принимает файл JSON и выполняет некоторую обработку с использованием пользовательских правил, основанных на информации внутри файла.Проблема, с которой я столкнулся в настоящее время, заключается в том, что я пытаюсь динамически определить, какой класс обслуживания использовать для обработки файла во время выполнения.Ниже моя текущая реализация:

Интерфейс

public interface DataService {

    public void loadData(String path);
}

Реализация 1

@Service
public class ClassA implements DataService {
    // some attributes...

    public void loadData(String path) {
        // implementation
    }
}

Реализация 2

@Service
public class ClassB implements DataService {
    // some attributes...

    public void loadData(String path) {
        // implementation
    }
}

Реализация 3

@Service
public class ClassC implements DataService {
    // some attributes...

    public void loadData(String path) {
        // implementation
    }
}

Использование класса

@Service
public class DataRunner {
    @Autowired
    private DataService dataService;

    @Value("${task.file}")
    private String taskFile;

    @PostConstruct
    public void init() {
        // process the incoming taskFile and derive an enum called DataSource

        dataService.loadData("/example/file/location"); // what I wish would work
    }
}

Так, как вы можетепосмотрите, что метод init в классе DataRunner просто желаемое за действительное на данный момент.Возможно ли с помощью Spring Boot динамически определить, какой класс обслуживания использовать во время выполнения?Или я должен делать что-то совершенно другое, чтобы достичь того, чего я хочу здесь?

Ответы [ 3 ]

3 голосов
/ 07 июня 2019

Вы можете ввести шаблон распознавателя, чтобы идентифицировать вашу реализацию во время выполнения

@Service
public class DataServiceResolver{

    @Autowired
    private DataService classA;

    @Autowired
    private DataService classB;

    @Autowired
    private DataService classC;

    public DataService resolve(Whatever whatever) {
         //process your input and find the enum dataSource;
         DataSource datasource = process(file);
         DataService dataService;
         switch datasource {
           case A:
              dataService = classA;
              break;
           case B:
              dataService = classB;
              break;

           case C:
              dataService = classC;
              break;
           default:
              dataService = classB;
          }
     return dataService

    }
}

, а в вашем классе DataRunner вы используете преобразователь, чтобы найти необходимую реализацию


@Service
public class DataRunner {

    @Autowired
    private DataServiceResolver dataServiceResolver;

    @Value("${task.file}")
    private String taskFile;

    @PostConstruct
    public void init() {
        // process the incoming taskFile and derive an enum called DataSource

        //call the resolver and resolve to the needed dataservice. whatever can be your taskFile, etc
        DataService dataService = dataServiceResolver.resolve(whatever);
        dataService.loadData("/example/file/location"); // what I wish would work
    }
}

2 голосов
/ 07 июня 2019

Indirection - отличный способ решения вычислительных задач. Я бы вставил DataServiceFactory вместо DataService напрямую и на этой фабрике передал бы перечисление DataSource. Пусть фабрика вернет соответствующий экземпляр DataService.

1 голос
/ 07 июня 2019

Если у вас есть сотни различных процессоров, вы можете зарегистрировать (внедрить) их в реестр в виде списка. Затем вы можете перебрать список регистраций, чтобы увидеть, какой процессор следует использовать (я решил реализовать регистрационную информацию как часть процессора)

public interface DataProcessor {
  public boolean supports(MyInput input);
  public MyOutput process(MyInput input);
}

@Service
public class YesDataProcessor implements DataProcessor {
  public boolean supports(MyInput input) {
    return input.getSomething().equals("yes");
  }

  public MyOutput process(MyInput input) {
    // ... transforming to output
    return 
  }
}

@Service
public class NoDataProcessor implements DataProcessor {
  public boolean supports(MyInput input) {
    return input.getSomething().equals("no");
  }

  public MyOutput process(MyInput input) {
    // ... transforming to output
    return output;
  }
}


@Service
public class MyDataProcessorRegistry {
  @Autowired
  private List<DataProcessor> processors;

  public Optional<DataProcessor> getProcessor(MyInput input) {
    return processors.stream().filter(p -> p.supports(input)).findFirst();
  }
}
...