lilydocs
HTTP APIWebSocketConsumer
Temeller3 dk okuma

Dependency injection

Servisleri kaydedin, bağımlılıklarını enjekte edin ve request scope üzerinden çözün.

Dependency injection, bir servisin ihtiyaç duyduğu başka servisleri container’dan almasını sağlar. Lily servis kaydını derive ile üretir; nesne oluşturma ve temizleme görevini container üstlenir.

Bağımlılıklar#

İlk uygulamanın lilyrs bağımlılığı yeterlidir:

TOML
lilyrs = { version = "0.1.0", features = ["http-api"] }

Injectable, ServiceTrait, InjectionError ve diğer DI tiplerini lilyrs::http_api üzerinden alın. Derive, facade yolunu tanır; ayrı lily_injectable_derive, lily_injection_registry, lily_error veya linkme bağımlılığı eklemeniz gerekmez. Link-time registry mimarinin parçasıdır; elle kayıt veya factory yazılmaz.

HTTP host’undan bağımsız bir servis kütüphanesi geliştiriyorsanız features = ["injection"] seçip lilyrs::injection::{Injectable, ServiceTrait} kullanabilirsiniz. http-api tek başına lilyrs::injection modülünü açmaz; HTTP uygulamasında yukarıdaki framework kökü yeterlidir.

Servis tanımlama ve kullanma#

GreetingPolicy uygulama boyunca paylaşılır. GreetingService her isteğin kapsamına aittir ve policy’yi enjekte eder. Controller, Scoped servisi action parametresinde alır.

di.rs
use std::sync::Arc;
use lilyrs::http_api::Injectable;
use lilyrs::http_api::{
    controller, Controller, ControllerInitError, ControllerTrait, Extensions,
    HttpApiError, Service, ServiceTrait,
};

#[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 message(&self) -> String { "Merhaba".to_owned() }
}

#[derive(Controller)]
#[base_path("/greetings")]
struct GreetingController { policy: Arc<GreetingPolicy> }

#[lilyrs::http_api::async_trait::async_trait]
impl ControllerTrait for GreetingController {
    async fn new(extensions: Arc<Extensions>) -> Result<Self, ControllerInitError> {
        let policy = extensions.get_service::<GreetingPolicy>(None).await
            .map_err(ControllerInitError::dependency)?;
        Ok(Self { policy })
    }
}

#[controller]
impl GreetingController {
    #[get("/")]
    async fn read(&self, Service(service): Service<GreetingService>)
        -> Result<String, HttpApiError>
    {
        Ok(service.message())
    }
}

GET /greetings başarılı olduğunda JSON string olarak "Merhaba" döner. Düz metin yanıt için PlainText kullanın; ayrıntılar yanıtlarda.

Constructor mı, action mı?#

Controller constructor’ı uygulama ömründe bir kez çalışır. Burada Singleton bağımlılık alabilirsiniz. Request-scoped bağımlılığı burada tutmayın; action’da Service<T> ile çözün. Aynı istek içindeki servisler aynı scope’u paylaşır.

Servis alanları#

#[inject] alanları Arc<T> veya Arc<dyn Trait> olmalıdır. Bütün named field’lar inject ediliyorsa Default gerekmez. Inject edilmeyen runtime alanı varsa struct Default sağlamalıdır. Bu derive için kanonik şekil named-field struct veya unit struct’tır; generic servis, tuple struct ve enum kullanılmaz.

Başlatma ve temizleme#

ServiceTrait::initialize(&mut self) nesne oluşturulurken, dispose(&self) sahibi kapanırken çalışır. Bunları handler’dan elle çağırmayın. Kapanış sırasında mutable durum gerekiyorsa shared erişime uygun senkronizasyon kullanın.

#[service(disabled)] derleme sırasında servis adayını kapatır; istek sırasında değiştirilen bir feature toggle değildir.

Bu sayfanın kaynakları v0.1.0

Anlatım, incelenen framework commit’ine dayanır.

HIZLI BAŞLANGIÇ
Dokümantasyon
Kaynak kod