• Anasayfa
  • Eğitimler
    • JavaScript Eğitimi
    • Angular 2 Eğitimi
    • React.js Eğitimi
    • Java 8 Eğitimi
    • Java EE 7 Eğitimi
    • Spring Framework Eğitimi
    • Git Eğitimi
  • Online Eğitimler
    • Online React.js Eğitimi
    • Online Angular 2 Eğitimi
    • Online Spring Boot Eğitimi
  • Referanslar
  • Hakkında
  • İletişim
KodEdu
  • Anasayfa
  • Eğitimler
    • JavaScript Eğitimi
    • Angular 2 Eğitimi
    • React.js Eğitimi
    • Java 8 Eğitimi
    • Java EE 7 Eğitimi
    • Spring Framework Eğitimi
    • Git Eğitimi
  • Online Eğitimler
    • Online React.js Eğitimi
    • Online Angular 2 Eğitimi
    • Online Spring Boot Eğitimi
  • Referanslar
  • Hakkında
  • İletişim

Java ServiceLoader Nedir? SPI (Service Provider Interface) Nasıl Yazılır?

  • Posted by Kodedu
  • Categories backend, Genel, Uncategorized, Yazılar, Yazılım
  • Date 23 Şubat 2015

Java programlama dilinde yazılan servisler, farklı servis sağlayıcıları tarafından uygulanabilmektedir. Servisler genel olarak arayüzler veya soyut sınıflar ile yazılırken, servis sağlayıcıları ise bu arayüz servislerini uygulayan uygulayıcı sınıflardır.

Java programlama dilinin 6. versiyondan beri bulunan java.util.ServiceLoader sınıfı ise, uygulamalarınızda yer alan farklı servis sağlayıcılarına erişerek, kullanmanıza imkan sağlamaktadır.

Örneğin bir servis yazarının RandomServiceProvider adında bize bir arayüz sunduğunu varsayalım;

public interface RandomServiceProvider {

    public Integer random(int start, int end);

}

RandomServiceProvider sınıfının bulunduğu projenin dizin yapısı aşağıdaki gibidir.

random service spi.png
Figure 1. random-service-spi projesi

Bu servisin görevi adından da anlaşılacağı üzere verilen iki tam sayı arasında rastegele bir sayı üretmesidir. Servis sağlayıcı sınıfları genel olarak arayüz veya soyut sınıf türünden olmaktadır.

Spesifikasyon belirleyicileri, farklı uygulayıcılar için yukarıdakine benzer arayüzleri API uygulayıcılarına açmaktadır. Java standartlarının geliştirim sürecine bakıldığında, buna benzer bir süreç sürdürülmektedir. API uygulayıcıları ise bu arayüzlere dönük kendi implementasyonlarını geliştirmektedir.

Fakat iş sadece arayüzü tanımlamak değildir, bunun yanında servis sağlayıcı kütüphanenin sisteminize standart bir yolla entegre edilebilmesi gerekmektedir. java.util.ServiceLoader sınıfı bu noktada, servis uygulayıcılarına standart arayüz servislerine eklenti olarak eklenme imkanı sunmaktadır. Örneğin şimdi, RandomServiceProvider arayüzünün kullanıcı talebine karşı farklı sağlayıcıları sunabiliyor olmasını sağlayalım. Bunun için bu servise iki statik metod daha ekleyeceğiz.

Java 8 ile birlikte arayüzlere static metodlar tanımlanabilmektedir. Java 8 öncesini kullanıyorsanız interface yerine abstract sınıfları da kullanabilirsiniz.
public interface RandomServiceProvider {

    public Integer random(int start, int end);

    public static RandomServiceProvider getProvider(String providerName) {
        return ...;
    }

    public static RandomServiceProvider getDefaultProvider() {
        return ...;
    }

}

RandomServiceProvider sınıfına getProvider ve getDefaultProvider adlarında iki statik metod ekledik. Bunlardan getDefaultProvider() çağrıldığında bu servisin varsayılan imlpementasyonunun kullanıcıya döndürülmesini istiyoruz. getProvider(..) olanla ise metoda sunulan sağlayıcı ismiyle X bir sağlayıcının döndürülmesini istiyoruz. İşte bu sağlayıcı sınıflar türünden uygulayıcı nesnelerin sistemde aranıp sunulması için ServiceLoader sınıfından faydalanacağız. Fakat bu metodların içerisini ServiceLoader ile yapılandırmadan evvel bir varsayılan sağlayıcı nesnesi oluşturma yoluna gidelim.

public class StandardRandomProvider implements RandomServiceProvider {

    @Override
    public Integer random(int start, int end) {
        Random random = new Random();
        int randomInt = random.nextInt((end - start + 1)) + start;
        return randomInt;
    }

}

Görüldüğü üzere RandomServiceProvider sağlayıcı arayüzünü uygulayan bir StandardRandomProvider sınıfı oluşturduk. Bu sınıf içerisindeki random() metodu, Random sınıfı üzerinden verilen aralıkta rastgele bir tamsayı üretmektedir.

ServiceLoader sınıfının, bu sağlayıcıya erişip yükleyebilmesi için, sağlayıcının belirli bir formda Java projesine kayıt ettirilmesi gerekmektedir. Bunun için StandardRandomProvider sınıfının yer aldığı projede META-INF/services dizini altında RandomServiceProvider sınıfının tam adıyla bir dosya oluşturulmalı ve bu dosyanın içine RandomServiceProvider sınıfının tam adı yazılmalıdır.

standard random service.png
Figure 2. standard-random-service projesi

com.kodcu.spi.RandomServiceProvider dosyasını içi ise aşağıdaki gibidir.

com.kodcu.spi.RandomServiceProvider dosyasının içi
com.kodcu.StandardRandomProvider

Bu şekilde artık StandardRandomProvider servisini ServiceLoader sistemine göre yapılandırmış oluyoruz. Artık ServiceLoader, sağlayıcı sınıfı arayıp bulabilir ve sisteme yükleyebilir.

Şimdi, RandomServiceProvider arayüz içini uygulayıcılarını sunar şekilde yapılandırmaya devam edelim.

public interface RandomServiceProvider {

public Integer random(int start, int end);

public static RandomServiceProvider getDefaultProvider() {
    return getProvider("com.kodcu.StandardRandomProvider"); (1)
}

public static RandomServiceProvider getProvider(String providerName) {
    ServiceLoader<RandomServiceProvider> serviceLoader = ServiceLoader.load(RandomServiceProvider.class); (2)

    for (RandomServiceProvider provider : serviceLoader) { (3)
        String className = provider.getClass().getName(); (4)
        if (providerName.equals(className)) (5)
            return provider;
    }

    throw new RuntimeException(providerName + " provider is not found!"); (6)
}

}
1 com.kodcu.StandardRandomProvider tam isimli varsayılan sağlayıcı sınıfını CLASSPATH ‘den yükler ve döndürür.
2 Yükleyeceği sağlayıcı arayüz türünden bir ServiceLoader nesnesi üretilir.
3 CLASSPATH içinde bulunan tüm RandomServiceProvider servis sınıfları türünden nesneler turlanır.
4 Bulunan RandomServiceProvider türünden sınıfın tam adı elde edilir.
5 Eğer bulunan sınıfın tam adı metoda düşen isimle aynı ise ilgili nesne metotdan döndürülür.
6 Eğer CLASSPATH içinde hiçbir servis uygulayıcısı bulunmadıysa bir istisna mesajı ile geliştirici bilgilendirilir.

Şimdi varsayılan StandardRandomProvider sağlayıcısına alternatif yeni bir sağlayıcı oluşturalım. İsmi ThreadedRandomProvider olsun.

public class ThreadedRandomProvider implements RandomServiceProvider {

    @Override
    public Integer random(int start, int end) {
        int randomInt = ThreadLocalRandom.current().nextInt(start,end);
        return randomInt;
    }
}

ThreadedRandomProvider sınıfı rastgele sayı üretme işini Random sınıfı yerine ThreadLocalRandom sınıfı üzerinden yapıyor. Tabiki bu servis sınıfını yine kendi projesinde META-INF/services altında yapılandırmalıyız.

threaded random service.png
Figure 3. threaded-random-service projesi

com.kodcu.spi.RandomServiceProvider dosyasını içi ise aşağıdaki gibidir.

com.kodcu.spi.RandomServiceProvider dosyasının içi
com.kodcu.ThreadedRandomProvider

Böylece RandomServiceProvider servisi StandardRandomProvider gibi ThreadedRandomProvider sınıfını da kullanıcılarına sunabilecektir.

Şimdi bu üç ayrı Java projeyesini random-service-spi , standard-random-service , threaded-random-service çalıştıran random-service-app adında bir proje oluşturalım. Bu proje random-service-spi servisi üzerinden iki servis sağlayıcısını yükleyecek ve random() metodlarını koşturacaktır.

public class App {

    public static void main(String[] args) {

        RandomServiceProvider defaultProvider = RandomServiceProvider.getDefaultProvider(); (1)

        System.out.println(defaultProvider.random(1,1000));  (2)

        RandomServiceProvider threadedProvider = RandomServiceProvider.getProvider("com.kodcu.ThreadedRandomProvider"); (3)

        System.out.println(threadedProvider.random(1,1000)); (4)
    }

}
1 RandomServiceProvider.defaultProvider() metodu üzerinden varsayılan servis sağlayıcısını com.kodcu.StandardRandomProvider yükler.
2 StandardRandomProvider ‘ın random() metodu ile rastgele bir sayı üretip çıktılar.
3 RandomServiceProvider.getProvider() metodu üzerinden com.kodcu.ThreadedRandomProvider servis sağlayıcısını yükler.
4 ThreadedRandomProvider ‘ın random() metodu ile rastgele bir sayı üretip çıktılar.

random-service-app projesinin dosya sistemindeki görünümü aşağıdaki gibidir.

random service app.png
Figure 4. random-service-app projesi

Böylece standart bir servise, ekler halinde ayrı uygulayıcılar tanıtmış olduk. ServiceLoader API ise biz geliştiricilere standart bir yol sunmuş oluyor. Bu yaklaşımın birçok popüler Java Framework’lerinde de kullanıyor olduğunu söylemeliyim.

Aşağıda servis ve iki uygulayıcısını ve bunları tüketen App sınıfını UML diagram halinde görebilirsiniz.

service provider uml.png

Kaynak kodlara buradaki bağlantıdan erişebilirsiniz.

Tekrar görüşmek dileğiyle

Tag:backend, service-loader, spi

  • Share:
author avatar
Kodedu

Previous post

First Look at JSR 371, MVC 1.0 Spesification and Ozark RI
23 Şubat 2015

Next post

Create Beautiful JavaFX Charts with AsciidocFX
4 Nisan 2015

You may also like

api-logo
Swagger Nedir? Neden kullanılır?
10 Ekim, 2018
spring-cli-logo
Spring CLI ile Spring Boot Projeleri Hazırlamak
21 Ağustos, 2017
eureka_architecture
Spring Cloud Netflix ve Eureka Service Discovery
3 Temmuz, 2017

Leave A Reply Cevabı iptal et

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

E-posta listesine kayıt olun!






Gözde yazılar

Java Mimarisiyle Kurumsal Çözümler : Kurumsal Java Kitabı
16Eyl2012
Java API for JSON Processing – Stream bazlı JSON Üretmek ve Tüketmek
06Ağu2013
AsciidocFX projesi Duke’s Choice Award 2015 ödülünü kazandı
28Eki2015
Knockout.js – Hesap Makinesi Örneği
02Şub2013

Son Yazılar

  • Java’da Record’lar 27 Ocak 2020
  • Swagger Nedir? Neden kullanılır? 10 Ekim 2018
  • Spring CLI ile Spring Boot Projeleri Hazırlamak 21 Ağustos 2017
  • Spring Cloud Netflix ve Eureka Service Discovery 3 Temmuz 2017
  • Online React.js Eğitimi ardından (15-25 Mayıs 2017) 31 Mayıs 2017

Son Yorumlar

  • Coupling ve Cohesion Kavramları Nedir? için Hilal
  • Naïve Bayes Sınıflandırma Algoritması için Rahman Usta
  • Naïve Bayes Sınıflandırma Algoritması için Mete
  • YAML Nedir? Neden YAML Kullanmalıyız? için kara
  • JWT (JSON Web Tokens) Nedir? Ne işe yarar? için Furkan

Get Java Software

Arşivler

Bizi takip edin

React.js Eğitimi Başlıyor
11-22 Eylül, 2017
Eğitmen
Rahman Usta
İletişim

merhaba@kodedu.com

  • Hakkında
  • Gizlilik Politikası
  • İletişim
  • Referanslar
Kodedu Bilişim Danışmanlık
Cemil Meriç mah. Çelebi sok.
No:16/3 Ümraniye/İSTANBUL
Tel: 0850 885 38 65
Alemdağ V.D.: 8960484815

KODEDU © Tüm hakları saklıdır.