CDI – @Produces, @New ve @PostConstruct Notasyonları
Merhaba arkadaşlar, CDI (Context and Dependency Injection) serisinin dördüncü yazısında sizlerle @Produces, @New ve @PostConstruct notasyonlarından birer örnek ile birlikte bahsetmek istiyorum. Önceki yazılarda kullandığımız gibi bir Arac arayüzü ve bu arayüzlere uyan iki somut sınıf (Araba ve Otobus) aşağıdaki diagramdan gözlenebilir. (Diğer yazılara buradan erişebilirsiniz -> Weld-1, Weld-2, Weld-3 )
@PostConstruct Notasyonu
Bu notasyon doğrudan JSR 346: Contexts and Dependency Injection for Java EE 1.1 belirtimi altında bulunmaktan ziyade, JSR 250 Commons Annotations belirtimi altında yer almaktadır. Görevi ise, bir nesne oluşturulduktan hemen sonra herhangi uygulanan bir metoda giriş sağlaması ve o metodu işletmesidir.
Örnek olarak aşağıdaki Araba sınıfını inceleyebiliriz.
@Default // olmasada olur
public class Araba implements Arac{
private int hiz;
@Override
public String calis() {
return "Araba "+hizSoyle()+" km. hızında çalışıyor..";
}
@PostConstruct
private void init(){
hiz = ThreadLocalRandom.current().nextInt(20, 240);
}
@Override
public int hizSoyle(){
return this.hiz;
}
}
Araba sınıfının Arac arayüzünden devşirdiği calis() ve hizSoyle() metodları ve ek olarak oluşturulan init() metodu yer almaktadır. init() metodunun başına dikkat edilirse, @PostConstruct notasyonuna sahip olduğu görülebilir. Bu noktada @PostConstruct notasyonu, Araba sınıfından bir nesne oluşturulduktan hemen sonra init() metodunun çalışmasını sağlayacak ve 20-240 değerleri arasında rastgele bir sayı üreterek, sınıf içerisindeki global hiz alanına aktaracaktır.
@PostConstruct metodu yalnızca metod başlarında uygulanabilen bir notasyon türüdür. Peki bunu nasıl anlayabiliriz? (Elbette kaynak koduna bakarak)
@Documented
@Retention (RUNTIME)
@Target(METHOD) // Dikkat
public @interface PostConstruct {
}
@Produces Notasyonu
Normal şartlarda her bir Java sınıfı, CDI tarafından enjekte edilebilir bir CDI nesnesidir. CDI teknolojisi sınıflarda olduğu gibi, global alanlardaki ve metod dönüşlerindeki değerlerin de enjekte edilebilir olması için @Produces notasyonunu bizlere sunmaktadır. @Produces notasyonunun kullanımını aşağıda bulunan Otobus ve Uretec sınıflarına bakarak öğrenebiliriz.
@Default
public class Otobus implements Arac {
@Inject
@Hiz // Hangi Integer?
private Integer hiz;
public String calis() {
return "Otobus "+ hizSoyle() +" km. hızında çalışıyor..";
}
public int hizSoyle(){
return this.hiz;
}
}
public class Uretec {
@Hiz // Buradan üretilen Integer
@Produces
public Integer uret() {
return ThreadLocalRandom.current().nextInt(20, 160);
}
/* veya
@Hiz
@Produces
private int hiz = ThreadLocalRandom.current().nextInt(20, 160);
*/
}
Uretec sınıfının uret() metoduna bakılırsa, başına @Produces notasyonu eklendiği görülebilir. Bu notasyon, uret() metodundan dönecek veriyi, CDI ortamı tarafından enjekte edilebilir bir veri adayı olarak işaretlemektedir. Bunun neticesinde ise, CDI konteyner ortamında Integer türünden enjekte edilmeye aday bir nesne eklenmiş olur. @Produces notasyonu sınıf tipinden nesneleri enjekte edilebilir kıldığı gibi, ilkel java tiplerinden verileri de enjekte edilebilir yapabilir.
Uretec#uret() metodundan dönen veri nasıl enjekte edilebilir? Bunun için Otobus sınıfının global hiz alanına bakılabilir. @Inject notasyonuyla @Produces aracılığıyla üretilen veri, bu alana enjekte edilmektedir. Peki Otobus sınıfında kullanılan @Inject notasyonu JDK içerisinde bulunan Integer sınıfından bir nesne oluşturup mu enjekte edecek? Yoksa bizim Uretec#uret() metodundan ürettiğimiz int değeri mi? Burada CDI ortamında enjekte edilebilir iki veri/nesne olacağından bir seçici ile seçim yapmak gereklidir. Bu örnekte kullanılan seçicimiz @Hiz notasyonudur.
@Qualifier
@Target(value = {ElementType.FIELD,ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Hiz {
}
Hız notasyonu metod ve global alan başlarında kullanılabilen bir @Qualifier notasyonu olarak yapılandırılmıştır.
@New Notasyonu
@New notasyonu javax.enterprise.inject paket yapısı atlında bulunan özel bir seçici notasyondur.
public class Galeri {
@Inject
@New(value=Araba.class) // new Araba(); gibi
private Arac arac;
@Inject
@New(Otobus.class) // new Otobus(); gibi
private Arac tasit;
@Inject
@New // new Arac(); gibi. Hata!!
private Arac motorlu;
public static void main(String[] args) {
Weld weld = new Weld();
WeldContainer konteyner = weld.initialize();
Galeri galeri = konteyner.instance().select(Galeri.class).get();
String aracMesaj = galeri.arac.calis();
System.out.println("> " + aracMesaj);
String tasitMesaj = galeri.tasit.calis();
System.out.println("> " + tasitMesaj);
}
}
Galeri sınıfı içerisinde @Inject notasyonu kullanılan üç global alan bulunmaktadır. Bu alanların hepsi birlikte Arac arayüzü türündendir. CDI konteyner ortamında Arac arayüzü türünden iki adet enjekte edilebilir tip vardır, bunlar; Araba ve Otobus ‘tür. Bu sebeple bir biçimde Araba mı, yoksa bir Otobus nesnesinin mi enjekte edileceği seçilmelidir. Bu noktada elbette seçicilerden faydalanmak gerekecektir. Bir önceki yazılarda kullanılan klasik seçiciler burada işimizi görebileceği gibi, CDI kütüphanelerinde bulunan @New gömülü seçicisi de kullanılabilmektedir.
@New notasyonu hangi türden nesnenin seçileceğini tayin etmektedir. @New notasyonunun value() adında bir tek alanı bulunmaktadır ve bu alan hangi türden nesnenin enjekte edileceğini belirtmektedir. Eğer value() elemanında bir sınıf tipi seçilmez ise, uygulanan alanın tipi cinsinden nesne enjekte edilmeye çalışılmaktadır. 12. satırdaki alanın tipi bir arayüz olduğundan ve arayüzler doğrudan oluşturulamadıklarından, “WELD-000816 Cannot determine constructor to use for public abstract interface class com.kodcu.Arac” benzeri bir mesaj ile kullanıcı uyarılır, işte bu yüzden arayüz alanları için bu kullanım biçimi önerilmez. Onun yerine value() alanına oluşturulacak somut sınıfın tanımlanması doğru kullanım biçimi olacaktır.
Uygulama çalıştırıldığında, aşağıdaki çıktıya benzer bir sonuç alınır.
Bu uygulamaya https://github.com/rahmanusta/Weld-SE-4 adresinden erişebilirsiniz.
Tekrar görüşmek dileğiyle.