[Python] 依赖注入的使用,多模块任务隔离
使用google/pinject(依赖注入库)搭建了一个多模块运行、相互隔绝的项目。
- 定义全局单例的依赖注入容器:
"""依赖注入容器""" from typing import Any, List, Type, TypeVar import pinject import pinject.finding class Ioc: """依赖注入容器""" _S = TypeVar("_S", bound="Ioc") _T = TypeVar("_T", bound=Any) _instance: _S = None def __init__(self): """初始化""" self.obj_graph = None @classmethod def __new__(cls, *args, **kwargs): """单例模式""" if cls._instance is None: cls._instance = super(Ioc, cls).__new__(cls) return cls._instance @classmethod def init(cls, binding_specs: List[pinject.BindingSpec]): """初始化""" if cls._instance is None: cls._instance = cls() cls._instance.obj_graph = pinject.new_object_graph( binding_specs=binding_specs, only_use_explicit_bindings=False ) @classmethod def provide(cls, obj_type: Type[_T]) -> _T: """获取对象""" return cls._instance.obj_graph.provide(obj_type)
依赖注入容器的绑定初始化:
binding_specs = [BindingSpec(), PumpBindingSpec()]
Ioc.init(binding_specs)
依赖注入容器的获取绑定:
Ioc.provide(PumpSpider) class PumpSpider: """Pump链爬虫""" @pinject.annotate_arg("log", "pump") @pinject.annotate_arg("selenium_engine", "pump") @pinject.annotate_arg("selenium_helper", "pump") @pinject.annotate_arg("element_helper", "pump") @pinject.annotate_arg("db_engine", "pump") @pinject.annotate_arg("upload_db_engine", "pump") def __init__( self, log: ILog, pump_config: PumpConfig, selenium_engine: SeleniumEngine, selenium_helper: SeleniumHelper, element_helper: ElementHelper, db_engine: DbEngine, upload_db_engine: DbEngine, ): """初始化""" // ...
- 绑定的定义:
- 通用绑定:
"""依赖注入绑定""" import pinject from selenium_utils.selenium_engine import SeleniumEngine from utils.log import Logger from utils.time_helper import NtpTime class BindingSpec(pinject.BindingSpec): """依赖注入绑定""" def configure(self, bind): """配置""" bind("log", to_class=Logger, in_scope=pinject.SINGLETON) bind("selenium_engine", to_class=SeleniumEngine, in_scope=pinject.PROTOTYPE) bind("ntp_time", to_class=NtpTime, in_scope=pinject.SINGLETON) @pinject.provides("network_log", in_scope=pinject.SINGLETON) def provide_network_log(self): """提供日志""" return Logger("network")
解释:
a. 配置了三个单例服务:
-
-
- log:使用Logger类,用于通用日志记录
- ntp_time:使用NtpTime类,提供时间服务
- selenium_engine:使用SeleniumEngine类,但采用原型模式(每次注入创建新实例)
-
b. 通过@provides装饰器提供了network_log服务,用于网络相关的日志记录
- pump模块定制化绑定:
"""依赖注入绑定""" import pinject from modules.pump.pump_config import PumpConfig from selenium_utils.element_helper import ElementHelper from selenium_utils.selenium_engine import SeleniumEngine from selenium_utils.selenium_helper import SeleniumHelper from selenium_utils.webdriver_extension import WebDriverExtension from sqlite.db_engine import DbEngine from utils.download_helper import DownloadHelper from utils.file_helper import FileHelper from utils.process_helper import ProcessHelper from utils.log import Logger class PumpBindingSpec(pinject.BindingSpec): """依赖注入绑定""" def configure(self, bind): """配置""" @pinject.provides("log", annotated_with="pump", in_scope=pinject.SINGLETON) def provide_pump_log(self): """提供日志""" return Logger("pump") @pinject.provides("network_log", annotated_with="pump", in_scope=pinject.SINGLETON) def provide_pump_network_log(self): """提供日志""" return Logger("pump_network") @pinject.provides("upload_log", annotated_with="pump", in_scope=pinject.SINGLETON) def provide_pump_upload_log(self): """提供日志""" return Logger("pump_upload") @pinject.provides( "process_helper", annotated_with="pump", in_scope=pinject.SINGLETON ) def provide_pump_process_helper(self): """提供进程助手""" return ProcessHelper(self.provide_pump_log()) @pinject.provides( "selenium_engine", annotated_with="pump", in_scope=pinject.PROTOTYPE ) def provide_pump_selenium_engine(self, pump_config: PumpConfig): """提供进程助手""" return SeleniumEngine( self.provide_pump_log(), self.provide_pump_network_log(), pump_config, self.provide_pump_file_helper, self.provide_pump_process_helper, ) @pinject.provides( "selenium_helper", annotated_with="pump", in_scope=pinject.SINGLETON ) def provide_pump_selenium_helper(self, pump_config: PumpConfig): """提供Selenium助手""" return SeleniumHelper( self.provide_pump_log(), pump_config, self.provide_pump_web_driver_extension(pump_config), ) @pinject.provides( "element_helper", annotated_with="pump", in_scope=pinject.SINGLETON ) def provide_pump_element_helper(self, pump_config: PumpConfig): """提供网页元素操作助手""" return ElementHelper( self.provide_pump_log(), pump_config, self.provide_pump_selenium_helper(pump_config), ) @pinject.provides( "web_driver_extension", annotated_with="pump", in_scope=pinject.SINGLETON ) def provide_pump_web_driver_extension(self, pump_config: PumpConfig): """提供WebDrider扩展方法""" return WebDriverExtension(self.provide_pump_log(), pump_config) @pinject.provides("db_engine", annotated_with="pump", in_scope=pinject.SINGLETON) def provide_pump_db_engine(self, pump_config: PumpConfig): """提供数据库引擎""" return DbEngine( "sqlite:///modules/pump/data.db", self.provide_pump_log(), pump_config ) @pinject.provides( "upload_db_engine", annotated_with="pump", in_scope=pinject.SINGLETON ) def provide_pump_upload_db_engine(self, pump_config: PumpConfig): """提供数据库引擎""" return DbEngine(pump_config.mysql_url, self.provide_pump_log(), pump_config) @pinject.provides("file_helper", annotated_with="pump", in_scope=pinject.SINGLETON) def provide_pump_file_helper(self): """提供文件助手""" return FileHelper(self.provide_pump_log()) @pinject.provides( "download_helper", annotated_with="pump", in_scope=pinject.SINGLETON ) def provide_pump_download_helper(self): """提供下载助手""" return DownloadHelper(self.provide_pump_log())
解释:
a. 上面定义了3个日志类,分别是log、network_log、upload_log,每个日志写入到不同的文件中,实现了日志的隔离。
b. 同理,上面定义的selenium_engine、db_engine、file_helper等与其他模块都是隔离的。
3. 项目运行流程图


分类:
Python
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本