状态管理
在 Zino 框架中,应用状态是由State类型提供的:
#[derive(Debug, Clone)]pub struct State<T = ()> {env: Env,config: Table,data: T,}
它包含有运行环境Env、TOML格式的配置文件Table以及自定义数据类型T。
不同于很多Web框架,我们的应用状态管理是基于惰性初始化的全局变量来实现的,主要考量如下:
- 应用状态通常存在于整个运行期间,也就是说它的生命周期为
'static; - 应用状态通常只需要初始化加载一次,并且在运行期间并不会被修改;
- 尽可能避免在
controller或service方法中传递应用状态参数。
回到具体实现上,最核心的几行代码就是
static SHARED_STATE: LazyLock<State> = LazyLock::new(|| {let mut state = State::default();state.load_config();state});
这定义了一个全局共享的静态变量,通过State::shared方法可以得到它的一个&'static引用,
然后就可以在整个应用中到处使用。
示例:如何使用Redis?
# config/config.dev.toml[redis]host = "127.0.0.1"port = 6379database = "dbnum"username = "some_user"password = "hsfU4Y3aRbxVNuLpVG5T+wb9jIDdQyaUIiPgeQrP0ZRM1g"
//! src/extension/redis.rsuse redis::{Client, Connection};use zino_core::{error::Error, state::State, LazyLock};#[derive(Debug, Clone, Copy)]pub struct Redis;impl Redis {#[inline]pub async fn connect() -> Result<Connection, Error> {REDIS_CLIENT.get_async_connection().await.map_err(Error::from)}}static REDIS_CLIENT: LazyLock<Client> = LazyLock::new(|| {let config = State::shared().get_config("redis").expect("the `redis` field should be a table");let database = config.get_str("database").expect("the `database` field should be a str");let authority = State::format_authority(config, Some(6379));let url = format!("redis://{authority}/{database}");Client::open(url).expect("fail to create a connector to the redis server")});
这是Zino框架中推荐的使用模式:在配置文件里编写Redis连接信息^password,通过Lazy的全局变量初始化Client; 然后定义一个空结构体,进而封装一些自定义方法。仔细想想,这不就类似于其他语言中的“单例模式”吗?
