Hizmet Yükleyici, içeren modül module-info.java tanımında bir provides ... with yönergesi bildirmediğinde sağlayıcıları bulamaz. Java Platform Modül Sistemi (JPMS), varsayılan olarak güçlü kapsüllemeyi zorunlu kılarak, Hizmet Yükleyicinin ( java.base içinde bulunan) dışa aktarılmamış veya açılmamış paketlerdeki sınıflara erişmesini engeller. provides yönergesi, Hizmet Yükleyiciye belirli sağlayıcı sınıfını örneklemek için ayrıcalıklı yansıtmalı erişim sağlamak üzere bir sözleşmesel beyan olarak işlev görür, bu da normal paket erişim kısıtlamalarını aşmasını sağlar ve paketin tüm modüllere dışa aktarılmasını gerektirmez.
Bağlam: Bir miras kurumsal CRM sistemi Java 8'den Java 17'ye taşınıyordu. Amaç, monolitik mimariyi belirgin alanlara ayırmaktı: crm-core, crm-email ve crm-api. crm-email modülü, crm-api içinde tanımlanmış NotificationService arayüzünün bir uygulamasını içeriyordu.
Taşınmanın ardından, uygulama başlangıçtan ServiceConfigurationError hatası fırlattı. Bu, EmailNotificationService sınıfının genel (public) olmasına ve JAR dosyalarının modül yolunda bulunmasına rağmen meydana geldi. Yığın izleme, hizmet türü için hiçbir sağlayıcının bulunmadığını göstererek, bildirim alt sisteminin başlatılamamasına neden oldu.
Problem: Geliştirme ekibi, uygulama sınıfının genel görünürlüğünün yeterli olduğunu düşündü. Bu, genel (public) sınıfların küresel olarak görünür olduğu sınıf yolu çağı varsayımlarını yansıtıyordu. Ancak, JPMS başkalarındaki dışa aktarılmamış paketlerdeki sınıflara erişimi engeller. crm-email modülü com.crm.email.internal paketini dışa aktarmıyordu. Kritik olarak, module-info.java dosyasında provides com.crm.api.NotificationService with com.crm.email.internal.EmailNotificationService beyanı yoktu. Sonuç olarak, Hizmet Yükleyici sağlayıcıyı bulamadı veya örnekleyemedi, çünkü modül sistemi uygulamayı kapsüllenmiş bir iç detay olarak değerlendirdi.
Değerlendirilen Çözümler:
Paketi Dışa Aktarma: crm-email modül tanımına exports com.crm.email.internal; eklemek. Bu yaklaşım, iç uygulama ayrıntılarını diğer modüllere açacağı için reddedildi. Kapsülleme ilkesine aykırıydı ve modül sisteminin tasarlandığı sıkı bağlanmayı oluşturuyordu.
Paketi Yansıtma için Açma: opens com.crm.email.internal; veya spesifik olarak opens com.crm.email.internal to java.base; kullanmak. Bu yansıtmalı erişime izin verse de, aşırı izin verici ve anlamsal olarak yanlış olduğu düşünüldü. Bu, paketin genel olarak derin bir yansıtma işlemine tabi olduğunu belirtir, oysa belirli bir mekanizma aracılığıyla hizmet sağlaması gerekmektedir.
provides ... with Yönergesini Kullanma: module-info.java dosyasına provides com.crm.api.NotificationService with com.crm.email.internal.EmailNotificationService; bildirisini eklemek. Bu, JPMS çözümüdür. Hizmet ilişkisini açıkça belirtir ve Hizmet Yükleyiciye sınıfı örneklemek için gerekli erişim haklarını verirken sıkı kapsüllemeyi korur.
Seçilen Çözüm: Ekip üçüncü seçeneği seçti. Bu yaklaşım, uygulama kodunun kendisinde herhangi bir değişiklik yapılmasını gerektirmedi. Paketin iç görünürlüğünü korudu ve hizmet bağımlılığını modül meta verilerinde açık hale getirdi.
Sonuç: Uygulama, çalışma zamanında EmailNotificationService'yi başarıyla yükledi. Modüler sınır sağlam kaldı, diğer modüllerin iç uygulama sınıflarını doğrudan örneklemesini veya buna bağımlı olmasını engelledi. Hizmet Yükleyici, bildirilen sözleşme aracılığıyla hizmeti doğru bir şekilde keşfetti ve sağladı.
Neden Hizmet Yükleyici, sağlayıcı sınıfının genel bir sıfır-argüman yapıcısına sahip olmasını gerektirir ve bu kısıtlama ihlal edilirse hangi özel istisna ortaya çıkar?
Hizmet Yükleyici, sağlayıcı sınıflarını yansıtma yoluyla Class.getConstructor().newInstance() kullanarak örnekler. Bu, kesinlikle genel bir hiç-argüman yapıcıyı gerektirir. Eğer bu yapıcı yoksa veya genel değilse, Hizmet Yükleyici bir ServiceConfigurationError fırlatır. Bu hata genellikle bir NoSuchMethodException veya IllegalAccessException etrafında sarılırken, yineleyici geçiş sırasında ortaya çıkar. Adaylar sıklıkla, başka yapıcılar tanımlıysa, bu yapıcının açıkça sağlanması gerektiğini göz ardı ederler. Ayrıca, örneklemenin Iterator.next() çağrıldığında gerçekleştiğini, başlangıçta ServiceLoader.load() çağrısında değil, unutur.
Hizmet Yükleyici mekanizması, hizmet arayüzü adlandırılmış bir modül içinde tanımlandığında, sağlama sınıflarını adlandırılmamış modüllerde nasıl ele alır?
Hizmet arayüzü, adlandırılmış bir modülde yer alıyorsa ancak uygulama bir adlandırılmamış modülde (sınıf yolu) bulunuyorsa, Hizmet Yükleyici yine de sağlayıcıyı bulabilir. Adlandırılmamış modüller, tüm adlandırılmış modülleri dolaylı olarak okur ve tüm adlandırılmış modüller, adlandırılmamış modülleri dolaylı olarak okur. Ancak, sağlayıcı sınıfının yine de genel (public) ve genel bir hiç-argüman yapıcısına sahip olması gerekir. Yaygın yanlış anlam, güçlü kapsüllemenin bu senaryoyu tamamen engellediğidir. Gerçekte, adlandırılmamış modül bir uyumluluk katmanı görevi görür. Adlandırılmamış modüllerdeki sağlayıcılara erişim, adlandırılmamış modülü açıkça okumayan adlandırılmış modüllerdeki kodlar tarafından sağlanamaz. Bu, adayların sıklıkla göz önünde bulundurmadığı yönlü bir erişim kısıtlaması yaratır.
ServiceLoader.loadInstalled() metodunu, sınıf yükleyici devri ve sağlayıcı görünürlüğü açısından ServiceLoader.load() metodundan ayıran nedir?
ServiceLoader.loadInstalled(), sağlayıcıları aramak için sistem sınıf yükleyicisini (veya modern JVM sürümlerinde platform sınıf yükleyicisini) kullanır. Sağlayıcı keşfini yalnızca yüklü uzantılar dizini veya platform modülleri ile sınırlıdır. Uygulama modül yolu veya sınıf yolundaki sağlayıcıları açıkça göz ardı eder. Buna karşılık, ServiceLoader.load() tipik olarak iş parçacığı bağlamı sınıf yükleyicisinden veya belirli bir sınıf yükleyicisinden yararlanır. Bu, uygulama düzeyindeki sağlayıcıları keşfetmesine olanak tanır. Adaylar bu yöntemleri sıklıkla karıştırır, bu da uygulama sağlayıcılarının bulunmadığı sessiz hatalara yol açar. Bu, loadInstalled()'ın yanlış kullanılması sonucu gerçekleşir, standart yükleme yöntemine benzer bir davranış beklentisiyle ama daha geniş bir görünürlükle.