如何动态确定要在运行时使用的服务 Class

How to Dynamically Determine Service Class To Use At Runtime

对于某些上下文,我有一个 java 应用程序,它接受一个 JSON 文件,并根据文件中的信息使用自定义规则进行一些处理。我目前遇到的问题是,我正在尝试动态确定 class 用于在 运行 时间处理文件的服务。下面是我当前的实现:

界面

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
    }
}

利用Class

@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
    }
}

因此,正如您所见,DataRunner 中的 init 方法 class 目前只是一厢情愿。是否可以通过 Spring 开机动态决定 class 在 运行 时使用哪个服务?还是我应该做一些完全不同的事情来实现我在这里想要的?

间接是解决计算问题的好方法。我会直接注入 DataServiceFactory 而不是 DataService,并在该工厂中传递 DataSource 枚举。拥有工厂 return DataService 的适当实例。

您可以引入解析器模式以在运行时识别您的实现

@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 class 中使用解析器找到所需的实现


@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
    }
}

如果您有数百个不同的处理器,您可以将它们作为列表注册(注入)到注册表中。然后您可以遍历注册列表以查看应该使用哪个处理器(我决定将注册信息作为处理器的一部分实现)

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();
  }
}