Java 基于相互依赖性的springbean排序

Java 基于相互依赖性的springbean排序,java,spring,sorting,Java,Spring,Sorting,我有一个Java8/Spring应用程序。定义了一个接口DataCalculator: public interface Calculator { public void calculate(Data data); } 我有几个实现这个接口的具体类,它们都用@Component注释,所以它们是SpringBean(singleton)。我想运行所有这些,因此我使用了自动连线列表: public class MyApplication { private List<Calc

我有一个Java8/Spring应用程序。定义了一个接口
DataCalculator

public interface Calculator
{
    public void calculate(Data data);
}
我有几个实现这个接口的具体类,它们都用
@Component
注释,所以它们是SpringBean(singleton)。我想运行所有这些,因此我使用了自动连线列表:

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);
            }
        }
    }
}
公共类MyApplication
{
私人名单计算器;
@自动连线//技术上不需要,为清晰起见添加
公共MyApplication(列表计算器)
{
这个。计算器=计算器;
}
公共void calculateAll(收集数据收集)
{
用于(数据:数据收集)
{
for(计算器:this.calculators)
{
计算器。计算(数据);
}
}
}
}
这是可行的,但我现在偶然发现了一个要求,即某些计算器依赖于其他计算器先完成。我认为有三种方法可以实现这一点,每种方法都有利弊:

  • 在需要首先运行的计算器上添加
    @Order(x)
    注释。赞成:简洁到程序。缺点:如果依赖性很高或很深,开发人员添加或编辑计算器是非常麻烦的。这些信息分散在所有的计算器上,而不是集中提供
  • 不要使用Springbean,而是实例化中心类中的所有计算器,并按首选顺序将它们添加到列表中。赞成者:非常清楚存在哪种秩序。缺点:我们失去了自动布线的自动电源。虽然声明的计算器的现有顺序是明确的,但插入新计算器并不总是显而易见的(并且可能只是在“只是为了确保”的末尾追加,而不是按类别分组)
  • 创建自定义注释
    @CalcDependency(value=OtherCalculator.class)
    ,并在计算器列表上运行拓扑排序算法,以便在使用它们之前对它们进行排序。赞成:排序逻辑在一个地方,每个计算器都表示它们所依赖的内容,而不是它们所具有的任意“顺序”。易于插入新计算器:只需声明依赖项,而不是顺序。(如果检测到周期性依赖项,则应抛出错误)缺点:大多数编程工作量似乎都太大了 想法?Spring是否有某种方式来声明在自动关联列表时需要考虑的依赖项


    我知道spring有一个
    @dependsOn
    注释,但在这种情况下这似乎没有什么用处。

    您可以编写包装类,它有一些顺序字段,您可以用来排序计算器,或者简单地将该字段添加到bean中,或者添加更多的接口。。。选项由您选择

    然后,简单地按“顺序”字段对计算器进行排序,并使用foreach

    下面的评论中询问了一个例子。(这完全不是产品代码,只是给您展示一个示例)


    可能的话,你能提供一个简短的代码示例吗?@AuntJemima更新了答案,希望它能对你有所帮助。在我的用例中,使用Spring的
    @Order
    注释有什么附加值?当然,你可以使用Order注释,它可以根据你的需要工作。您还可以声明一些常量类,这些常量类将显示“排序级别”,例如:NO_DEPENDENCIES=1,dependens_SOMETHING_FROM_LEVEL_1=2 dependens_SOMETHING_FROM_LEVEL_2=3。。另外,当您从上下文接收集合时,需要对它们进行排序,而不是它们添加到上下文中的顺序。因此,在这种情况下,您可以轻松忽略DependsOn注释。此外,您需要以某种方式对收藏进行排序。您可以轻松地编写自己的比较器,并以某种方式列出依赖项,从而解决问题。
    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