[Python] 依赖注入的使用,多模块任务隔离

使用google/pinject(依赖注入库)搭建了一个多模块运行、相互隔绝的项目。
  1. 定义全局单例的依赖注入容器:
    复制代码
    """依赖注入容器"""
    
    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,
    ):
        """初始化"""
        // ...
复制代码
  1. 绑定的定义:
    1. 通用绑定:
      复制代码
      """依赖注入绑定"""
      
      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服务,用于网络相关的日志记录

    1. 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. 项目运行流程图

0
0
 
posted @   孤独成派  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示