我有一个Java8 / Spring应用程序。定义了一个接口DataCalculator
:
public interface Calculator
{
public void calculate(Data data);
}
我有几个实现此接口的具体类,它们都用@Component
注释,因此它们是Spring bean(单个)。我想运行所有这些,所以我使用了自动装配的列表:
public class MyApplication
{
private List<Calculator> calculators;
@Autowired //Technically not needed, added for clarity
public MyApplication(List<Calculator> calculators)
{
this.calculators = calculators;
}
public void calculateAll(Collection<Data> dataCollection)
{
for(Data data : dataCollection)
{
for(Calculator calculator : this.calculators)
{
calculator.calculate(data);
}
}
}
}
这可行,但是我偶然发现某些计算器必须先依赖其他计算器才能完成的要求。我看到了三种实现方式,每种都有优点/缺点:
@Order(x)
批注。优点:程序简洁。缺点:如果依赖关系数量很大或很深,开发人员添加或编辑计算器会非常麻烦。信息分散在所有计算器上,而不是集中可用。@CalcDependency(value = OtherCalculator.class)
,并在计算器列表上运行拓扑排序算法以对它们进行排序,然后再使用它们。优点:排序逻辑放在一个地方,每个计算器都表达它们所依赖的内容,而不是它们所具有的任意“顺序”。易于插入新计算器:您只需声明依赖项,而不是顺序。 (如果检测到周期性依赖关系,则将引发错误)缺点:要编写大量的工作,似乎有点过头了。 有什么想法吗? Spring是否有某种方式声明依赖项,因此在自动装配列表时会予以考虑?
我知道spring有一个@dependsOn
注释,但这在这种情况下似乎没有用。
答案 0 :(得分:1)
您可以编写包装器类,该包装器类具有一些可用于对计算器进行排序的顺序字段,或者可以将该字段简单地添加到bean或添加更多接口...选项供您选择。
在您的“ order”字段中进行简单排序的计算器之后,使用foreach。
示例在下面的评论中问。 (这完全不是生产就绪的代码,只是为了向您展示示例)
package org.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.Comparator;
import java.util.List;
@Configuration
@ComponentScan
public class Main {
@Autowired
List<Calculator> calculators;
public void start() {
calculators.stream().sorted(Comparator.comparing(Calculator::getOrder)).forEach(Calculator::calculate);
}
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(Main.class);
ctx.refresh();
Main main = ctx.getBean(Main.class);
main.start();
}
}
interface Calculator {
void calculate();
int getOrder();
}
@Component
class FirstCalc implements Calculator {
@Override
public void calculate() {
System.out.println(String.format("firstCalc with order %s", getOrder()));
}
@Override
public int getOrder() {
return 1;
}
}
@Component
class SecondCalc implements Calculator {
@Override
public void calculate() {
System.out.println(String.format("secondCalc with order %s", getOrder()));
}
@Override
public int getOrder() {
return 1;
}
}
@Component
class ThirdCalc implements Calculator {
@Override
public void calculate() {
System.out.println(String.format("thirdCalc with order %s should be 3rd", getOrder()));
}
@Override
public int getOrder() {
return 2;
}
}
@Component
class FourthCalc implements Calculator {
@Override
public void calculate() {
System.out.println(String.format("lastCalc with order %s should be last", getOrder()));
}
@Override
public int getOrder() {
return 3;
}
}
结果将是:
firstCalc with order 1
secondCalc with order 1
thirdCalc with order 2 should be 3rd
lastCalc with order 3 should be last