ITPub博客

首页 > 数据库 > 数据库开发技术 > 水文一篇~聊聊Fastapi中进行动态切换依赖注入项

水文一篇~聊聊Fastapi中进行动态切换依赖注入项

原创 数据库开发技术 作者:程序员小钟同学 时间:2023-10-28 18:28:20 0 删除 编辑

依赖注入和控制反转

首先在谈依赖注入的时候,我们需要了解一个概念,那就是控制反转。

首先我们需要明白一点,控制反转是一种软件设计原则,它的主要作用是把将以往我们传统的控制流程反转,将对象的创建和管理责任交给框架或容器,使得应用程序的各个组件更加松散耦合,,更加方便管理和分离组件。也就是说,当我们某个在构建某个应用程序的时候,应用所需的各个部件不再负责直接创建或查找它们所依赖的对象,而是通过某种外部机制(例如框架或容器)来获得所需的依赖的组件项。这样做的好处是降低了组件之间的耦合度,使得代码更加灵活、可扩展和可测试。

接着我们需要了解。依赖注入(Dependency Injection)和控制反转(Inversion of Control)是紧密相连的概念,而这里我们的依赖注入它就是控制反转的一种实现方式,它是一种设计模式的定义,它通常用于将依赖关系从一个对象传递给另一个对象,用于解耦,避免繁琐相互嵌套声明实例化等操作。

通俗的来说,所谓的控制反转类似加入我需要自己打造专属摩托车,按传统的方式流程:

  • 我--走路--去市场--采集相关配件或零件--自己打包---带着零件自己回家---然后进行拼装

有了控制反转和依赖注入后,上面整个流程我们可以把部分的流程给外包(独立出来,相当交付给第三方进行处理),如:

  • 我---拼兮兮买配件,并负责邮递(外包第三方)---到家进行拼接。

在上面的流程中 “依赖注入” 就像是拼兮兮平台一样通过参数的方式把相关配置传递到你家,而不需要再向前面一样自己逛街自己淘货,啥事都亲力亲为就太累了~ 这样后续需要啥,就直接找拼夕夕下单就可以了~~~

PS:注意拼夕夕~懂得都懂~有毒~~~~~~~~~

依赖注入示例

在FastAPI中框架中,引入相关的依赖注入,我们主要目的是将外部资源或数据的创建和管理责任交给框架,以减少代码的耦合度。

而依赖注入的表现形式是,通过将依赖项作为参数传递给函数或类的方式来注入到指定的app对象或路由对象等中。

基于这个特性其实对于我们编写API接口来说是非常有用,它可以让我们进行一些公共代码逻辑的复用。如下示例代码所示:

from fastapi import Depends, FastAPI

app = FastAPI()

async def get_db_connection():
    # 创建数据库连接的逻辑
    return "数据库连接对象"

@app.get("/")
async def root(db: str = Depends(get_db_connection)):
    # 通过依赖注入返回的db对象
    return {"message": "Hello World"}

如上代码的示例中,get_db_connection函数被定义为一个依赖项,并通过Depends(get_db_connection)将其注入到root请求处理函数中,并赋值给了db。接着我们可以在函数内部使用db来进行相关连接处理。而对于上面中get_db_connection则就是一个依赖项。

依赖注入应用场景总结

  • 单元测试:通过将依赖项注入到被测试对象中,你可以轻松地模拟或替换依赖项,以进行单元测试。

  • 插件和扩展:通过使用依赖注入,你可以轻松地添加、替换或扩展应用程序的功能,而无需修改原始代码。

  • 重复利用公共逻辑代码块。

  • 应用的认证和授权。

  • 数据库事务管理。

动态切换依赖项

加入我们某种场景需要进行动态依赖注入项的切换时候,我们可以基于下面的方式进行实现:


from fastapi import Depends, FastAPI

app = FastAPI()

# 定义两个不同的依赖项函数,用于模拟不同的依赖项
async def dependency_a():
    return "依赖性A"

async def dependency_b():
    return "依赖性B"

# 定义一个依赖注入函数,根据条件选择不同的依赖项
def dynamic_dependency(condition: str):
    async def dependency():
       # Python 3.10里面的Match-Case语法详解
        match condition:
            case 'A':
                return await dependency_a()
            case 'B':
                return await dependency_b()
            case _:
                return "木有依赖性"
    return dependency

# 使用动态依赖注入生成路由处理函数
@app.get("/dynamic1")
async def dynamic_route(dependency: str = Depends(dynamic_dependency('A'))):
    return {"message": f"Using dependency: {dependency}"}

# 使用动态依赖注入生成路由处理函数
@app.get("/dynamic2")
async def dynamic_route(dependency: str = Depends(dynamic_dependency('B'))):
    return {"message": f"Using dependency: {dependency}"}

if __name__ == "__main__":
    # 使用os.path.basename函数获取了当前文件的名称,并将.py文件扩展名替换为空字符串\
    # import os
    # app_modeel_name = os.path.basename(__file__).replace(".py", "")
    from pathlib import Path
    # 使用Path函数获取了当前文件的名称,并将.py文件扩展名替换为空字符串\
    # app_modeel_name = Path(__file__).name.replace(".py", "")
    import uvicorn
    import inspect
    # 根据文件路径返回模块名
    # print("app_modeel_name:",inspect.getmodulename(Path(__file__).name))
    # 使用uvicorn.run函数运行了一个应用程序。它指定了应用程序的主机和端口,并且设置了reload参数为True。
    uvicorn.run(app, host='127.0.0.1', port=33294)

在上面的代码中,我们分别访问不同的API接口可以看到可以根据句路由API接口指定的参数进行不同依赖项的返回,但是这好像还是没有实现到我们动态切换。有没有其他更优雅的方式呐?

框架给我们提供了一个 app.dependency_overrides的属性,它主要是可以再运行时随时切换已注入的依赖项,如下代码示例所示:

from fastapi import Depends, FastAPI

app = FastAPI()

async def original_dependency():
    return "依赖性A Dependency"

async def override_dependency():
    return "依赖性B Dependency"

@app.get("/")
async def get_dependency(dependency: str = Depends(original_dependency)):
    return {"当前模式为:": dependency}



@app.get("/change1")
async def get_dependency():
    app.dependency_overrides[override_dependency] = original_dependency
    return '切换成功为 original_dependency '

@app.get("/change2")
async def get_dependency():
    app.dependency_overrides[original_dependency] = override_dependency
    return '切换成功为 override_dependency '

在上面的代码中,我们预定义了两个依赖项,分别是:

  • original_dependency
  • override_dependency

接着假设我们需要通过另外的接口调整下面路由的依赖性从original_dependency--依赖变为--->override_dependency依赖,:

@app.get("/")
async def get_dependency(dependency: str = Depends(original_dependency)):
    return {"当前模式为:": dependency}

那么我此时只需要再相关逻辑里面动态进行切换没,如下切换的API接口,就是进行从original_dependency--依赖变为--->override_dependency依赖的请求:

@app.get("/change2")
async def get_dependency():
    app.dependency_overrides[original_dependency] = override_dependency
    return '切换成功为 override_dependency '

同理另外的接口就是切换回来。如此我们就可以再运行时动态进行依赖项替换了。

水文一篇~文笔有限,如有笔误或错误!欢迎批评指正!感谢各位大佬!有什么问题也可以随时交流!

结尾

END

简书:https://www.jianshu.com/u/d6960089b087

掘金:https://juejin.cn/user/2963939079225608

公众号:微信搜【程序员小钟同学】

新开QQ群号,欢迎随时加群交流,相互学习。QQ群号:247491107

小钟同学 | 文 【欢迎一起学习交流】| QQ:308711822


原文作者:程序员小钟同学;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2021-02-20

  • 博文量
    224
  • 访问量
    111686