Skip to main content

Container

Struct Container 

Source
pub struct Container { /* private fields */ }
Expand description

DI 服务容器 — 服务注册/解析/生命周期管理

对齐 PHP app()->bind()/make()/singleton()/instance()/scoped()/alias()。 使用 TypeId 作为 key 实现类型安全的服务解析,避免 PHP 字符串 key 的类型不匹配风险。

§线程安全

  • bindingsinstancesscoped_instancesaliases 均使用 RwLock 保护
  • 单例实例以 Arc 返回,可跨线程共享

Implementations§

Source§

impl Container

Source

pub fn new() -> Self

创建空的服务容器

Source

pub fn bind<T, F>(&self, factory: F)
where T: Send + Sync + 'static, F: Fn() -> T + Send + Sync + 'static,

注册瞬态服务(每次 make 创建新实例)

对齐 PHP app()->bind('key', fn() => new Service())

§类型约束
  • T: Send + Sync + 'static:服务实例必须线程安全
  • F: Fn() -> T + Send + Sync + 'static:工厂必须线程安全
Source

pub fn singleton<T, F>(&self, factory: F)
where T: Send + Sync + 'static, F: Fn() -> T + Send + Sync + 'static,

注册单例服务(整个应用生命周期内只创建一次)

对齐 PHP app()->singleton('key', fn() => new Service())

首次 make 时调用工厂创建实例并缓存,后续 make 返回缓存的同一实例。

Source

pub fn scoped<T, F>(&self, factory: F)
where T: Send + Sync + 'static, F: Fn() -> T + Send + Sync + 'static,

注册请求作用域服务(同一 ScopeId 内单例)

对齐 PHP app()->scoped('key', fn() => new Service())

singleton 不同:scoped 服务在 Container::make_with_scope 调用时, 同一 scope_id 内首次调用工厂创建并缓存,后续返回缓存; 不同 scope_id 各自创建独立实例;请求结束后调用 Container::clear_scope 清理对应作用域的缓存。

§用法
use sz_rust_core::container::{Container, ScopeId};

let container = Container::new();
container.scoped(|| RequestCache::new());

// 请求 A(scope_id=1)
let cache_a1 = container.make_with_scope::<RequestCache>(1).unwrap();
let cache_a2 = container.make_with_scope::<RequestCache>(1).unwrap();
assert!(Arc::ptr_eq(&cache_a1, &cache_a2)); // 同一作用域:同一实例

// 请求 B(scope_id=2)
let cache_b = container.make_with_scope::<RequestCache>(2).unwrap();
assert!(!Arc::ptr_eq(&cache_a1, &cache_b)); // 不同作用域:不同实例

// 请求 A 结束
container.clear_scope(1);
Source

pub fn instance<T>(&self, instance: T)
where T: Send + Sync + 'static,

直接绑定已创建的实例(绕过工厂)

对齐 PHP app()->instance('key', $obj)

将一个已创建的实例直接注册为单例,后续 make 返回此实例。 适用于:

  • 实例已在其他地方创建(如配置加载时初始化的服务)
  • 实例创建过程复杂、不适合用闭包表达
  • 测试中注入 mock 实例
§用法
use sz_rust_core::container::Container;

let container = Container::new();
let logger = Arc::new(FileLogger::new("/var/log/app.log"));
container.instance(logger.clone());

let resolved = container.make::<FileLogger>().unwrap();
assert!(Arc::ptr_eq(&logger, &resolved));
Source

pub fn alias<T: 'static>(&self, name: impl Into<String>)

为服务类型注册字符串别名

对齐 PHP app()->alias('name', Service::class)

别名仅用于:

解析时仍用类型安全的 make::<T>(),不支持通过字符串别名解析 (Rust 类型系统要求编译时已知类型,字符串 key 解析会引入不安全的 downcast)。

§用法
use sz_rust_core::container::Container;

let container = Container::new();
container.singleton(|| MyService::new());
container.alias::<MyService>("my_service");

assert!(container.is_alias("my_service"));
let type_id = container.resolve_alias("my_service").unwrap();
assert_eq!(type_id, std::any::TypeId::of::<MyService>());
Source

pub fn resolve_alias(&self, name: &str) -> Option<TypeId>

通过别名查找对应的 TypeId

返回 None 表示别名未注册。

Source

pub fn is_alias(&self, name: &str) -> bool

检查指定别名是否已注册

Source

pub fn debug_aliases(&self) -> Vec<String>

列出所有已注册别名(用于调试)

Source

pub fn make<T: Send + Sync + 'static>(&self) -> Option<Arc<T>>

解析服务实例(无作用域)

对齐 PHP app()->make('key')

等价于 Container::make_with_scope 传入 scope_id = 0。 对于 Scoped 生命周期服务,会使用 scope_id = 0 作为默认作用域。

§返回
  • Some(Arc<T>):服务已注册,返回实例(单例返回缓存实例,瞬态返回新实例)
  • None:服务未注册
§Panics

理论上不会 panic(工厂返回的 Box<dyn Any> 内部类型由编译时泛型保证)。 若发生 panic 说明内部状态被破坏(bindings 与 instances 不一致)。

Source

pub fn make_with_scope<T: Send + Sync + 'static>( &self, scope_id: ScopeId, ) -> Option<Arc<T>>

解析服务实例(带作用域 ID)

对齐 PHP app()->make('key') + 请求作用域支持。

§生命周期处理
  • Singleton:忽略 scope_id,返回全局缓存的单例
  • Transient:忽略 scope_id,每次调用工厂创建新实例
  • Scoped:同一 scope_id 内首次调用工厂创建并缓存,后续返回缓存
§返回
  • Some(Arc<T>):服务已注册,返回实例
  • None:服务未注册
§Panics

理论上不会 panic(工厂返回的 Box<dyn Any> 内部类型由编译时泛型保证)。 若发生 panic 说明内部状态被破坏。

Source

pub fn clear_scope(&self, scope_id: ScopeId)

清理指定作用域的所有缓存实例

应在请求结束时调用(如 axum 中间件在请求处理完毕后调用), 释放该作用域内创建的所有 Scoped 服务实例。

§用法
use sz_rust_core::container::Container;

let container = Container::new();
container.scoped(|| RequestCache::new());

let scope_id = generate_scope_id(); // 如从 axum State 获取
let _cache = container.make_with_scope::<RequestCache>(scope_id);

// 请求结束
container.clear_scope(scope_id);
Source

pub fn has<T: 'static>(&self) -> bool

检查服务是否已注册

Source

pub fn forget<T: 'static>(&self)

移除指定类型的服务绑定(含单例缓存与所有作用域缓存)

对齐 PHP app()->remove('key')

Source

pub fn clear(&self)

清空所有服务绑定与缓存(含单例、作用域、别名)

Source

pub fn count(&self) -> usize

已注册服务数量(不含别名)

Source

pub fn alias_count(&self) -> usize

已注册别名数量

Source

pub fn active_scope_count(&self) -> usize

当前活跃作用域数量

可用于检测作用域泄漏(如请求结束未调用 clear_scope)。

Trait Implementations§

Source§

impl Debug for Container

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Container

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<R, P> ReadPrimitive<R> for P
where R: Read + ReadEndian<P>, P: Default,

Source§

fn read_from_little_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_little_endian().
Source§

fn read_from_big_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_big_endian().
Source§

fn read_from_native_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_native_endian().
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more