【发布时间】:2019-08-12 09:45:05
【问题描述】:
首先,请让我介绍一个最小的场景演示来解释问题。
假设我有一个策略模式界面。
public interface CollectAlgorithm<T> {
public List<T> collect();
}
以及此策略的实现,ConcreteAlgorithm。
public class ConcreteAlgorithm implements CollectAlgorithm<Integer> {
@Resource
QueryService queryService;
@Override
public List<Integer> collect() {
// dummy ...
return Lists.newArrayList();
}
}
如您所见,实现依赖于@Service 组件提供的一些查询操作。
ConcreteAlgorithm类在某些地方会被new创建,然后会调用collect方法。
我已经阅读了一些相关链接,例如Spring @Autowired on a class new instance,并且知道上面的代码无法运行,因为new 创建的实例有一个@Resource 注释成员。
我是 Spring/Java 的新手,我想知道是否有一些方法或不同的设计可以使上述场景工作。
我考虑过使用工厂方法,但由于我提供了一个通用接口,它似乎会涉及许多未经检查的类型分配。
更新
为了更清楚,我添加了一些关于问题的细节。
我为一些消费者提供了一个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);
}
}
如您所见,我将通过用户传递字段创建不同的上下文,代表不同的推荐策略。所有的上下文都应该返回List<Long>,但是上下文中的管道是完全不同的。
上下文流程流水线一般有三个主要阶段。每个阶段的逻辑可能是复杂多样的。因此存在另一层策略模式。
public abstract class TemplateRecommendContextImpl<CollectOut, PredictOut> implements TemplateRecommendContext {
private CollectAlgorithm<CollectOut> collectAlgorithm;
private PredictAlgorithm<CollectOut, PredictOut> predictAlgorithm;
private PostProcessRule<PredictOut> postProcessRule;
protected List<CollectOut> collect(TemplateRecommendDTO recommendDTO){
return collectAlgorithm.collect(recommendDTO);
}
protected List<PredictOut> predict(TemplateRecommendDTO recommendDTO, List<CollectOut> predictIn){
return predictAlgorithm.predict(recommendDTO, predictIn);
}
protected List<Long> postProcess(TemplateRecommendDTO recommendDTO, List<PredictOut> postProcessIn){
return postProcessRule.postProcess(recommendDTO, postProcessIn);
}
public /*final*/ List<Long> process(TemplateRecommendDTO recommendDTO){
// pipeline:
// dataCollect -> CollectOut -> predict -> Precision -> postProcess -> Final
List<CollectOut> collectOuts = collect(recommendDTO);
List<PredictOut> predictOuts = predict(recommendDTO, collectOuts);
return postProcess(recommendDTO, predictOuts);
}
}
至于一个特定的RecommendContext,它的创建如下:
public class ConcreteContextImpl extends TemplateRecommendContextImpl<GenericTempDO, Long> {
// collectOut, predictOut
ConcreteContextImpl(){
super();
setCollectAlgorithm(new ShopDecorateCrowdCollect());
setPredictAlgorithm(new ShopDecorateCrowdPredict());
setPostProcessRule(new ShopDecorateCrowdPostProcess());
}
}
【问题讨论】:
-
“ConcreteAlgorithm 类在某些地方会被 new 创建”为什么?
-
为什么不呢?也许他正在创建控制台来实现这样的算法,而应用程序将根据用户的输入动态地创建这样的服务。在运行时创建 bean 有什么问题吗?
-
@m.antkowicz 是的,在基于 Spring 的应用程序中使用
new的想法是错误的 -
@Andrew Tobilko 为什么?我不知道诸如“在 Spring 中永远不要使用
new”之类的规则——例如,您希望如何在不创建服务类的情况下对它们进行单元测试? -
知道上面的代码是行不通的,因为new创建的实例有一个@Resource注解的成员。严格来说是假的。您只需要自己提供所需的实例。或者在您提到的帖子中显示实例创建后进行自动装配。
标签: java spring spring-boot autowired