Servisler ve injection
Paylaşılan bağımlılıkları controller’a, mesaj boyunca yaşayan servisleri aktif DI scope’una bağlayın.
Lily HTTP, WebSocket ve Consumer ortak DI altyapısını kullanır. lily_injection container ve scope'ları, lily_injectable_derive servis kaydını, lily_injection_registry kayıt altyapısını sağlar.
Bağımlılıklar#
İlk uygulamadaki bağımlılık yeterlidir:
lilyrs = { version = "0.1.0", features = ["websocket"] }Injectable, ServiceTrait, InjectionError, container ve scope tiplerini lilyrs::websocket üzerinden alın. Makrolar facade'i bulur; lily_injectable_derive, lily_injection_registry, lily_error ve linkme uygulamanıza ayrıca eklenmez. Registry, link-time keşfin iç altyapısı olarak kalır; manuel servis listesi yazmayın. Servis modülünü uygulamanın derlenen modül ağacına dahil edin.
Framework'ten bağımsız bir servis kütüphanesi yazıyorsanız features = ["injection"] seçip lilyrs::injection::{Injectable, ServiceTrait, InjectionError} kullanın. websocket feature'ının DI'yı içeride etkinleştirmesi public lilyrs::injection modülünü açmaz. lilyrs::di veya private expansion yollarını kullanmayın. BaseGateway, doğrudan crate yolları üreten ayrı bir makro olduğu için kendi bağımlılık istisnasını açıkça tanımlar.
Constructor ve mesaj injection’ı#
Bu örneği src/di.rs olarak kaydedip crate köküne mod di; ekleyin:
use std::sync::Arc;
use lilyrs::websocket::Injectable;
use lilyrs::websocket::ServiceTrait;
use lilyrs::websocket::{Ack, Extensions, Service, WebSocketActionError, WebSocketController,
WebSocketControllerInitError, WebSocketControllerTrait, async_trait, websocket_controller};
#[derive(Injectable)]
#[service(lifetime = "Singleton")]
struct GreetingPolicy;
impl ServiceTrait for GreetingPolicy {}
#[derive(Injectable)]
#[service(lifetime = "Scoped")]
struct GreetingService {
#[inject]
policy: Arc<GreetingPolicy>,
}
impl ServiceTrait for GreetingService {}
impl GreetingService {
fn greeting(&self) -> String { "Merhaba".into() }
}
#[derive(WebSocketController)]
#[namespace("greetings")]
struct GreetingController { policy: Arc<GreetingPolicy> }
#[async_trait]
impl WebSocketControllerTrait for GreetingController {
async fn new(extensions: Arc<Extensions>) -> Result<Self, WebSocketControllerInitError> {
let policy = extensions.get_service::<GreetingPolicy>(None).await
.map_err(WebSocketControllerInitError::dependency)?;
Ok(Self { policy })
}
}
#[websocket_controller]
impl GreetingController {
#[message("read")]
async fn read(&self, Service(service): Service<GreetingService>)
-> Result<Ack<String>, WebSocketActionError>
{ Ok(Ack::new(service.greeting())) }
}GreetingPolicy Singleton'dır; constructor'da extensions.get_service::<GreetingPolicy>(None) ile çözülür. Controller app boyunca bu instance'ı paylaşabilir. GreetingService Scoped'dur; Service<GreetingService> extractor'ı onu greetings:read mesajının aktif scope'undan alır.
Aynı scope içinde paylaşım#
Aynı mesajdaki middleware, guard ve action aynı Scoped servisi çözerse aynı örneği kullanır. Sonraki mesaj için yeni scope açılır. Controller constructor'ı mesaj scope'unda çalışmadığından Scoped servisi controller alanına koymayın.
Service<T> bir parts extractor'dır. Action imzasında payload'dan sonra yazılması önce çözülmesini engellemez; framework bütün parts extraction'ı payload tüketiminden önce yapar.
Başlatma ve temizlik#
Async kaynak açılışı ServiceTrait::initialize(&mut self), cleanup ise dispose(&self) içindedir. Controller, guard ve middleware için ayrı async dispose callback'i yoktur; veritabanı veya bağlantı gibi yönetilen kaynakları DI servisine yerleştirin.
Lifetime belirtilmezse Transient seçilir. Rehberde niyeti görünür kılmak için lifetime açık yazılır. Bütün named alanlar inject ediliyorsa Default gerekmez; inject edilmeyen runtime alanlarının ilk değerlerini üretmek için Default gerekir. Scope ve interface sayfası paylaşım sınırlarını ayrıntılandırır.
Bu sayfanın kaynakları v0.1.0
Anlatım, incelenen framework commit’ine dayanır.