Spring ve ApplicationContext Hiyerarşisi

Parent-Child ApplicationContext’ler

Spring tarafından yönetilen nesnelerin yer aldığı, Spring Container olarak da bilinen ApplicationContext bir uygulama içerisinde birden fazla sayıda oluşturulabilir. Bu ApplicationContext nesneleri arasında parent-child ilişki kurulabilir. Aslında Spring Web MVC ile çalışan, DispatcherServlet konfigüre edilen web uygulamalarında çoğu zaman bu bilinçli veya bilinçsiz biçimde uygulanıyor. DispatcherServlet kendisine ait bir WebApplicationContext oluşturur. Eğer web.xml içerisinde ContextLoaderListener tanımı mevcut ise web uygulamasının context’i initialize edilirken ayrı bir WebApplicationContext daha oluşmaktadır. İşte bu ikinci container, DispatcherServlet tarafından oluşturulan container’ın parent’ıdır. Aynı web uygulaması içerisinde çoğu zaman bir tane tanımlansa bile, gerektiği durumlarda birden fazla DispatcherSevlet tanımı yapılabilir. Bu durumda her bir DispatcherServlet instance’ının kendine ait bir Spring Container’ı olduğu gibi, bütün bu container nesneleri ContextLoaderListener tarafından oluşturulan WebApplicationContext’in child container’ı durumundadır.


Yukarıdaki diagramda da görüldüğü gibi birden fazla ApplicationContext instance’ı uygulamanın farklı katmanlarındaki Spring bileşenlerini yönetmek için ideal bir yapı sunmaktadır. Web katmanına ait olan controller, view gibi bileşenler DispatcherServlet’in ApplicationContext’i tarafından yönetilirken iş ve veri erişim katmanında yer alan servis ve DAO gibi bileşenlerin ise parent ApplicationContext tarafından yönetilmesi söz konusudur. Hemen aklımıza aynı uygulama içerisinde birden fazla DispatcherServlet’in nerede karşımıza çıkacağı sorusu gelebilir. Normal web request’lerini ele alan DispatcherServlet konfigürasyonumuza ilave olarak örneğin Spring Web Services Framework’ünü kullanarak contract-first yaklaşımı ile web uygulamamızdan belirli web servis çağrılarına da cevap vermesini isteyebiliriz. Spring Web Services Framework web servis çağrılarını MessageDispatcherServlet ile ele almaktadır ve kendine ait bir ApplicationContext oluşturmaktadır. Yine benzer biçimde Spring Remoting kabiliyeti ile servis katmanımızı ayrı bir DispatcherServlet konfigürasyonu ile standalone Java istemcilerin erişimine de sunabiliriz.

Ortak Bir ApplicationContext’in Paylaşılması

Yukarıda bahsettiğimiz model aynı JVM içerisinde çalıştırılan birden fazla web uygulamasına da uyarlanabilir. İki veya daha fazla web uygulaması servis, dao vb. bileşenleri ortak bir parent ApplicationContext nesnesi üzerinden paylaşabilirler. Örneğin birkaç web uygulaması ortak bir domain modeli paylaşabilirler ve persistence işlemleri de Hibernate gibi bir ORM aracı vasıtası ile gerçekleştirilebilir. Hibernate SessionFactory nesnesinin ve diğer ilgili bileşenlerin, servis ve dao bileşenlerinin konfigürasyonu bu web uygulamaları tarafından paylaşılabilir. Bu durumda belirtilen bileşenlerin ortak bir ApplicationContext içerisinde yönetilmesi gerekir. Spring kullanan web uygulamalarında ortak ApplicationContext’in oluşturulması ve bu container içerisindeki bileşenlere erişilebilmesi için öncelikle ApplicationContext’in de bir Spring bileşeni olarak tanımlanması gerekir.Bu tanım beanRefContext.xml isimli Spring bileşen konfigürasyon dosyası içerisinde yapılır.

<bean id="shared.context">
    <constructor-arg value="classpath*:/appcontext/appContext.xml"/>
</bean>

Yukarıdaki “shared.context” isimli bileşen tanımı bir ApplicationContext nesnesidir. Bu ApplicationContext de kendi içinde “classpath*:/appcontext/appContext.xml” argümanı ile classpath’deki ilgili konfigürasyon dosyalarını işleyerek kendi Spring bileşenlerini oluşturmaktadır. “shared.context” isimli ApplicationContext nesnesi diğer web uygulamalarında oluşturulan WebApplicationContext nesnelerine parent container olacaktır. Bunun için her bir web uygulamasının web.xml dosyası içerisinde

<context-param>
    <param-name>parentContextKey</param-name>
    <param-value>shared.context</param-value>
</context-param>

şeklinde bir context parametre tanımı yapılmalıdır. Bu sayede parentContextKey ile belirtilen bileşen ContextLoaderListener ile yaratılan WebApplicationContext’e parent ApplicationContext olarak belirtilmiş olunur. Peki “shared.context” ismi ile belirtilen bileşenin oluşturulması ve web uygulamaları arasında paylaştırılması işini kim gerçekleştirmektedir? Bu iş için BeanFactoryLocator arayüzünü implement eden bir nesneye ihtiyaç vardır. BeanFactoryLocator nesnesi parentContextKey ile belirtilen container instance’ı oluşturmak ile görevlidir. Birden fazla web uygulamasının aynı parent container instance’ı paylaşması için de Spring’in ContextSingletonBeanFactoryLocator sınıfından yararlanılır. Adından da anlaşılacağı gibi bu BeanFactoryLocator singleton olup, classpath’deki bütün beanRefContext.xml dosyalarını tespit eder. Bu konfigürasyon dosyalarındaki tanımlardan bileşenleri oluşturur. Daha önceden de belirttiğimiz gibi “shared.context” isimli ApplicationContext nesnesi de bir bileşen olarak beanRefContext.xml dosyasında tanımlanmıştı. Dolayısı ile context’i initialize olan ilk web uygulaması ortak ApplicationContext’in oluşmasını tetikleyecek ve bunu parent container olarak kullanacak, diğer web uygulamaları da singleton BeanFactoryLocator vasıtası ile aynı ApplicationContext nesnesine erişeceklerdir. Bu yöntemle ApplicationContext paylaşımının yapılabilmesi için beanRefContext.xml dosyalarının, Spring ile ilgili kütüphanelerin ve paylaşılan bütün bileşenlerle ilgili sınıf ve kütüphanelerinin web uygulamaları tarafından erişilebilen ortak bir lokasyonda olması şarttır. Bu çoğunlukla ear içerisine, web uygulamalarının ayrı war dosyaları olarak konarken, ortak dosya, sınıf ve kütüphanelerin de konması ile gerçekleştirilir. Tomcat gibi bir web container ile çalışırken ise ortak kısımlar Tomcat’in shared dizini altına yerleştirilir. Burada dikkat edilmesi gereken en önemli hususlardan birisi ContextSingletonBeanFactoryLocator sınıfını içeren spring-context.jar’ın da ortak lokasyonda olmasıdır. Aksi takdirde her bir web uygulamasının ayrı ClassLoader’ı olacağından farklı BeanFactoryLocator nesneleri oluşacak, dolayısı ile “shared.context” isimli ApplicationContext’de birden fazla olacaktır. Parent ApplicationContext yöntemi daha çok ortak bileşenlerin birden fazla web uygulaması arasında paylaşılması için kullanılsa bile, standalone uygulamaların modüler bir yapıya sahip olması için de kullanılabilir. BeanFactoryLocator kullanarak modüler bir mimarinin nasıl oluşturulabileceğine ise bir sonraki yazımızda değineceğiz.