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:
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.
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.