Java 新依赖@Service成员操作创建的实例

Java 新依赖@Service成员操作创建的实例,java,spring,spring-boot,autowired,Java,Spring,Spring Boot,Autowired,首先,请允许我介绍一个最小的场景演示来解释这个问题 假设我有一个策略模式接口 public interface CollectAlgorithm<T> { public List<T> collect(); } 如您所见,实现依赖于@Service组件提供的一些查询操作 ConcreteAlgorithm类将在某些地方由new创建,然后调用collect方法 我读过一些相关链接,如,并且知道上面的代码无法工作,因为new创建的实例有一个@Resource注释的成

首先,请允许我介绍一个最小的场景演示来解释这个问题

假设我有一个策略模式接口

public interface CollectAlgorithm<T> {
    public List<T> collect();
}
如您所见,实现依赖于@Service组件提供的一些查询操作


ConcreteAlgorithm类将在某些地方由new创建,然后调用collect方法

我读过一些相关链接,如,并且知道上面的代码无法工作,因为new创建的实例有一个@Resource注释的成员

我是Spring/Java新手,我想知道是否有一些方法或不同的设计可以让上述场景正常工作

我曾考虑过使用工厂方法,但由于我提供了一个通用接口,它似乎会涉及许多未经检查的类型分配

public interface CollectAlgorithm<T> {
    public List<T> collect();
}
使现代化 为了更清楚,我添加了一些关于这个问题的细节

我为一些使用者提供RPC服务,接口如下:

public interface TemplateRecommendService {
    List<Long> recommendTemplate(TemplateRecommendDTO recommendDTO);
}

@Service
public class TemplateRecommandServiceImpl implements TemplateRecommendService {

    @Override
    public List<Long> recommendTemplate(TemplateRecommendDTO recommendDTO) {
        TemplateRecommendContext context = TemplateRecommendContextFactory.getContext(recommendDTO.getBizType());
        return context.process(recommendDTO);
    }
}
相反,od使用面向字段的自动连接使用面向构造函数的自动连接-这将强制创建实现实例的用户在创建新实例时提供适当的依赖关系


根据您的品味和要求,我可以想出4+1奖励的可能方法

1.在构造函数中传递服务。 创建ConcreteAlgorithm类的实例时,提供QueryService的实例。您的算法可能需要扩展基类

    CollectAlgorithm<Integer> myalg = new ConcreteAlgorithm(queryService);
    ...
这是标准的,通常是春季的首选方式。当您提前知道所有可能的算法是什么,并且这些算法是无状态的时,它就会起作用。 这是典型的情况。我不知道它是否适合你的需要,但我希望大多数人都在寻找这种特殊的选择

注意,在上述场景中,建议使用基于构造函数的注入。换句话说,我将对您的实现进行如下修改:

    @Component
    public class ConcreteAlgorithm implements CollectAlgorithm<Integer> {

        final QueryService queryService;

        @Autowired
        public ConcreteAlgorithm(QueryService queryService) {
            this.queryService = queryService;
        }

        @Override
        public List<Integer> collect() {
            // dummy ...
            return Lists.newArrayList();
        }
    }
这在类似于1的场景中有效,但使您不再需要向构造函数传递参数,这在某些情况下可能有助于消除反射。 但是,我不支持这个特定的解决方案,因为它迫使您知道必须在调用其他方法之前调用setQueryService方法。非常容易出错

4.将QueryService直接传递给collect方法。 可能是最简单的解决办法

    public interface CollectAlgorithm<T> {
        public List<T> collect(QueryService queryService);
    }

    public class ConcreteAlgorithm implements CollectAlgorithm<Integer> {

        @Override
        public List<Integer> collect(QueryService queryService) {
            // dummy ...
            return Lists.newArrayList();
        }
    }

如果您希望您的界面是一个功能性的界面,并在集合中使用,那么这一点非常有效

奖励:Spring的SCOPE_原型 Spring不仅允许实例化单例bean,还允许原型bean。这实际上意味着它将充当您的工厂

我将通过以下URL将其留给外部示例:


这在特定场景中可能很有用,但我不想马上推荐它,因为它要麻烦得多。

在某些地方,ConcreteAlgorithm类将由new创建为什么?为什么不?也许他正在创建控制台来实现这样的算法,应用程序将根据用户的输入动态创建这样的服务。在运行时创建bean有什么问题吗?@m.antkowicz是的,在基于Spring的应用程序中使用new的想法是错误的wrong@Andrew托比尔科为什么?我不知道类似“永不在Spring中使用new”这样的aby规则——例如,您希望如何在不创建服务类的情况下对它们进行单元测试?我知道上面的代码无法工作,因为new创建的实例有一个@Resource注释的成员。严格地说,这是错误的。您只需要自己提供所需的实例。或者在创建实例后进行自动连接,如您提到的帖子所示。他的问题是,他无法使用新的实例化服务,因为缺少queryService—使用我的方法,如果没有符合IOC的依赖项,他将无法创建实例—Spring仍将在上下文中自动提供beanCreationSpring将在您的示例中提供哪一个bean?QueryService,当您将在其他地方自动连接具体算法时-严重的问题在哪里?我写的东西是否有误导性或错误?@AndrewTobilko它允许在创建过程中手动提供依赖项作为ctor参数。@m.antkowicz由xxx版本的Spring提供,如果ctor注释是唯一定义的构造函数,则可以使用它。谢谢您的建议。那么每次实例化ConcreteAlgorithm时的性能问题又如何呢?对于选项2,性能影响在应用程序启动时移动,因为算法对象是单例的。对于选项3和4,性能影响取决于算法的构造函数,请尽可能简单。对于选项1,它取决于构造函数,如果您最终使用它,则取决于反射开销,这可能是最大的影响。然而,优化的第一条规则是不要优化。这意味着,如果您的代码简单且编写良好,那么就不需要像反射y这样的花哨东西
在出现实际问题之前,您可以推迟考虑性能。对于选项2,我应该如何创建具体的算法?仍然使用新的ConcreteAlgorithm?不,使用选项2,您可以像为您的服务所做的那样注入算法:使用@Resource或@Autowired,具体取决于您的需要。您可能还需要检查@Qualifier注释。当然,只有当您可以共享您的算法实例时,选项2才起作用,即:它们是无状态的。
    CollectAlgorithm<Integer> myalg = new ConcreteAlgorithm(queryService);
    ...
    @Component
    public class ConcreteAlgorithm implements CollectAlgorithm<Integer> {

        @Resource
        QueryService queryService;

        ....

    }
    @Component
    public class ConcreteAlgorithm implements CollectAlgorithm<Integer> {

        final QueryService queryService;

        @Autowired
        public ConcreteAlgorithm(QueryService queryService) {
            this.queryService = queryService;
        }

        @Override
        public List<Integer> collect() {
            // dummy ...
            return Lists.newArrayList();
        }
    }
    CollectAlgorithm<Integer> myalg = new ConcreteAlgorithm();
    myalg.setQueryService(queryService);
    ...
    public interface CollectAlgorithm<T> {
        public List<T> collect(QueryService queryService);
    }

    public class ConcreteAlgorithm implements CollectAlgorithm<Integer> {

        @Override
        public List<Integer> collect(QueryService queryService) {
            // dummy ...
            return Lists.newArrayList();
        }
    }