基于YAML配置,使用Dependency Injector注入不同接口实现
基于YAML配置动态注入接口实现(dependency injector)
核心思路
通过配置文件指定实现类名称,结合dependency injector的Selector提供者或自定义工厂方法,从预定义的实现类注册表中动态选择并注入对应实例。
步骤1:编写YAML配置文件
在配置文件中明确指定要使用的实现类名称,例如:
配置文件1(使用Impl1):config_impl1.yaml
implementation: some_interface: Impl1
配置文件2(使用Impl2):config_impl2.yaml
implementation: some_interface: Impl2
步骤2:修改容器类实现动态选择
方法1:使用providers.Selector(推荐)
利用dependency injector内置的Selector提供者,根据配置值直接匹配对应的实现类,并用Singleton保证单例:
import abc from dependency_injector import containers, providers class SomeInterface(abc.ABC): @abc.abstractmethod def some_method(self): pass class Impl1(SomeInterface): def some_method(self): print("File-based implementation") class Impl2(SomeInterface): def some_method(self): print("Service-based implementation") class Container(containers.DeclarativeContainer): config = providers.Configuration(strict=True) # 实现类注册表:映射类名字符串到实际类 _impl_registry = { "Impl1": Impl1, "Impl2": Impl2, } # 动态选择实现类并创建单例实例 some_implementation = providers.Singleton( providers.Selector( config.implementation.some_interface, **_impl_registry ) )
方法2:自定义工厂方法
如果需要更灵活的逻辑(比如参数处理、默认值),可以用工厂方法结合@providers.Singleton装饰器:
class Container(containers.DeclarativeContainer): config = providers.Configuration(strict=True) _impl_registry = { "Impl1": Impl1, "Impl2": Impl2, } @providers.Singleton def some_implementation(self) -> SomeInterface: # 从配置中获取实现类名称,注册表中匹配对应类 impl_name = self.config.implementation.some_interface() impl_class = self._impl_registry.get(impl_name) if not impl_class: raise ValueError(f"Unsupported implementation: {impl_name}") return impl_class()
步骤3:加载配置并使用
保持原有的配置加载逻辑,获取实例时会自动根据配置选择对应实现:
# 加载Impl1的配置 container = Container() container.config.from_yaml("config_impl1.yaml", required=True) impl = container.some_implementation() impl.some_method() # 输出: File-based implementation # 切换为Impl2的配置 container.config.from_yaml("config_impl2.yaml", required=True) impl = container.some_implementation() impl.some_method() # 输出: Service-based implementation
注意事项
- 注册表的键必须与YAML配置中的类名字符串完全一致(区分大小写)。
- 如果需要给实现类的构造函数传递依赖,可以在
Selector中添加参数,或在工厂方法中从容器获取其他服务。 - 若配置中指定的实现类不在注册表中,可添加默认值或异常处理逻辑,避免程序崩溃。
内容的提问来源于stack exchange,提问作者David Clarke
相关产品推荐
相关产品推荐

