11 Aralık 2012 Salı

Spring ve Bean Yaratılması

Not : Dependency Injection sınıflar arasındaki bağımlılığı azaltırken altyapıya olan bağımlılığı artıyor.
Dependency injection increases coupling by requiring the user of a subsystem to provide for the needs of that subsystem.

1. Spring İçindeki Olayları Dinlemek

Spring Container da diğer tüm container tarzı yazılımlar gibi, kendisine abone olunup Observer tasarım örüntüsünün kullanılmasına imkan tanımaktadır. Bu durumu gösteren şekli buradan aldım. Böylece ApplicationListener arayüzü vasıtasıyla bir çok olayı öğrenmek mümkün.



2. Spring ve Bean'lerin Yaratılması

2.1 Bean Yaratılmadan Önce

Aşağıdaki şekli buradan aldım. Bean yaratılmadan önce BeanFactoryPostProcessor ile bean tanımında değişiklik yapabilmek mümkün.



Aşağıdaki şekilde ise BeanFactoryPostProcessor arayüzünden türeyen bazı sınıfları görmek mümkün.


2.2 Bean Yaratıldıktan Sonra

Spring içindeki bean'lerin yaşam döngüsünü (lifecycle) bir nebzeye kadar detaylandırmak mümkün. Bunun için kullanılabilecek 3 yöntem var.

  1. BeanPostProcessor Yöntemi
  2. XML içinde Custom Metod  Yöntemi
  3. InitializingBean ve DisposableBean Yöntemi
BeanPostProcessor Yöntemi
Bu başlığı ikiye ayırmak lazım. Birincisi Spring içinde tanımlı olan BeanPostProcessor sınıfları, ikincisi ise kendi tanımladığımız sınıflar.
Spring içinde tanımlı olan BeanPostProcessor sınıfları
BeanPostProcessorYöntemi burada anlatılıyor. Örneğin <tx:annotation-driven> XML cümlesi ile BeanPostProcessor yöntemi aracılığıyla transaction yönetimi gerçekleştiriliyor. Bir bean yaratılmadan önce bir BeanPostProcessor @Transactional anotasyonu kullanılmışmı diye kontrol ediyor ve eğer kullanılmışsa yaratılmak istenen bean için bir proxy üretiyor.

Bir başka örnek olarak org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor sınıfına da bakılabilir. Bu sınıf ile ilgili güzel bir örnek te burada bulunabilir.

Bu sınıf sayesinde @Autowired, @Inject, @Resource gibi tagler kullanılabiliyor.

Bu sınıfı Spring'e dahil etmek için <context:annotation-config /> veya <context:component-scan> XML cümlelerini eklemek yeterli. Bu ikisi arasındaki farkı anlamak için Difference between <context:annotation-config> vs <context:component-scan> başlıklı yazıya bakabilirsiniz.

<context:component-scan> ile @Component, @Repository, @Service ve @Controller olarak işaretli bean'ler Spring'e dahil ediliyor. Eğer bu taglerden bazılar hariç bırakılmak istenirse aşağıdaki gibi yapılabilir.

<context:component-scan base-package="com.java.test.app org.java.support">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

Kendi Tanımladığımız BeanPostProcessor Sınıfları
Buradaki örnekte Spring ile yaratılan bir bean nesnesinin Guava EventBus nesnesine eklenmesi örneği var.
 

Custom Metod Yöntemi
Bu yöntemde XML içinde bean'in çağırılacak metodu belirtliyor.

InitializingBean ve DisposableBean Yöntemi
Bu yöntemde bean InitializingBean ve DisposableBean arayüzlerinde türetiliyor.

Yöntemler arasında öncelik sırası bulunmakta. Bu öncelik sırasını gösteren bir şekli burada buldum.

Görüldüğü gibi InitializingBean arayüzü tarafından istenen afterPropertiesSet() metodu custom init metodundan önce çağırılır. Aynı zamanda DisposableBean arayüzü tarafından istenen destroy() metodu da yine custom destroy metodundan önce çağırılır.



Benzer bir şekli ise burada buldum.


InitializingBean yöntemi Spring'e mahsus. JSR-250 ile @PostConstruct ve @PreDestroy  tagleri tanımlanmış. Using JSR-250's @PostConstruct Annotation to Replace Spring's InitializingBean başlıklı yazıda da anlatıldığı gibi Spring'e mahsus bu arayüzler yerine @PostConstruct ve @PreDestroy anotasyonlarının kullanımı tercih edilmelidir.

2.3 new() ile Yaratılan Bean'ler
How to inject dependencies into a self-instantiated object in Spring? sorusunda da cevaplandığı gibi AutowireCapableBeanFactory arayüzü kullanılarak manuel olarak yaratılmış olan bir bean'e de dependency injekte edilebilir.


2.4 Bean ve Yaratılış Kapsamı (Scope)

Spring ile default gelen scope singleton scope'tur. Yani container bir bean'i bir defa yarattıktan sonra onu önbellekte saklar ve tekrar istenirse yine aynı nesneyi döndürür. Bu durum gösteren bir şekli buradan aldım.

Konuyu daha iyi açıklayan bir örneği ise burada bulabilirsiniz.


1 yorum: