构造函数注入API代理与添加作用域服务的性能对比
两种LogicAPI实现方式的优劣对比分析
我们目前同时采用两种LogicAPI的实现方式,想了解二者在性能等方面的优劣差异,以下是具体对比:
性能差异
从性能角度看,两者几乎没有本质区别:
- 示例1通过DI容器的Scoped生命周期注册,每个HTTP请求会创建一个新的LogicAPI实例;
- 示例2在控制器构造函数中直接实例化,同样是每个请求创建一次实例。
唯一需要注意的是示例1中使用了IHttpClientFactory来创建HttpClient,它会自动管理HttpClient的连接池,避免频繁创建销毁导致的socket资源耗尽问题。如果示例2中的SurveyApiSettings是直接创建HttpClient而非复用连接池,长期运行可能会出现性能瓶颈。
可维护性与扩展性
- 示例1采用依赖注入,控制器依赖的是抽象接口
ILogicAPI而非具体实现类,符合依赖倒置原则。后续如果需要替换LogicAPI的实现(比如换成MockLogicAPI、CachedLogicAPI),只需要修改DI注册代码,不需要改动控制器,扩展性极强。 - 示例2直接在控制器中
new具体类,代码耦合度极高。一旦LogicAPI的构造函数参数变化或者需要替换实现,所有手动实例化的控制器都要逐一修改,维护成本随着项目规模扩大急剧上升。
测试友好性
- 示例1的方式天生适合单元测试:在测试时可以轻松注入
ILogicAPI的Mock对象,完全隔离真实业务逻辑,快速验证控制器的逻辑正确性。 - 示例2直接实例化具体类,单元测试时无法隔离依赖,必须依赖LogicAPI的真实实现(甚至可能依赖外部服务),测试速度慢、不稳定,还容易出现测试污染。
依赖管理与生命周期控制
- 示例1由DI容器统一管理所有依赖:如果LogicAPI后续新增了依赖(比如需要IConfiguration、ILogger),只需要在注册时添加对应的服务,控制器代码完全不需要修改,容器会自动注入所有依赖。同时如果LogicAPI实现了
IDisposable,容器会在请求结束后自动调用Dispose方法释放资源,避免内存泄漏。 - 示例2需要手动管理所有依赖:每次新增依赖都要在控制器构造函数中手动传递,容易遗漏;如果LogicAPI需要释放资源,还要手动在控制器中处理,增加了出错的风险。
总结
如果只看性能,两种方式差异极小,但从长期维护、测试、扩展性角度来看,示例1的依赖注入方式绝对是更优选择。示例2的硬编码实例化方式只适合极小的Demo项目,在生产环境中会带来大量技术债,建议逐步统一为DI注入的实现方式。
示例代码
示例1:将ILogicAPI注入控制器构造函数
注册服务代码:
services.AddScoped<ILogicAPI, LogicAPI>(sp => { var httpClient = sp.GetRequiredService<IHttpClientFactory>().CreateClient(); return new LogicAPI(surveyConfig.SurveyApiProxyConfiguration(httpClient)); });
控制器代码:
public AssessmentController( SurveyUIConfiguration configuration, IAssessmentAPI assessmentApi, ISurveyReviewAPI surveyReviewApi, IAnswerAPI answerApi, ITakerScreenAPI screenApi, ILogicAPI logicApi, IMasterSurveyErrorMessageTextsAPI errorAPI ) { this.assessmentApi = assessmentApi; this.surveyReviewApi = surveyReviewApi; this.answerApi = answerApi; viewModelService = new ViewModelService(configuration, answerApi, screenApi, logicApi, errorAPI); }
示例2:在控制器中实例化LogicAPI
控制器代码:
public AssessmentController( IMasterSurveyErrorMessageTextsAPI errorAPI, IBaseSurveyControllerServices services ) : base(services) { this.assessmentApi = new AssessmentAPI(SurveyApiSettings); this.surveyReviewApi = new SurveyReviewAPI(SurveyApiSettings); this.answerApi = new AnswerAPI(SurveyApiSettings); var screenApi = new TakerScreenAPI(SurveyApiSettings); var logicApi = new LogicAPI(SurveyApiSettings); viewModelService = new ViewModelService(Configuration, answerApi, screenApi, logicApi, errorAPI); }
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

