Bu dokümanın hazırlanmasında base aldığım dokümanın sahibi ve bu konuları anlamamda bana çok emeği geçen kişi Arman Altuğ ÖZHAN‘dır. Canı gönülden teşekkürlerimi sunuyorum.

 

Bu doküman Java EE teknolojileri kullanılarak ADF ile proje geliştirebilmek üzerine daha çok persistence ve control katmanı konusunda bilgiler içermektedir. Çok katmanlı mimari göz önüne alınarak tasarlanan sistem göz önüne alınmıştır. ADF teknolojisinin business (EO xml leri ve VO lar) modeli kullanılmadan ADF projelerinin geliştirilebilmesi açıklanmıştır.

Model katmanı

Bu bölüm genellikle EJB3.0 ve buna bağlı olarak geliştirilmiş tekrar kullanılabilir objeler ile sağlanan alt yapı kullanılarak proje geliştirme aşamalarının üzerinden geçmektedir.

Üzerinden geçilecek başlıklar:

1. Entity Beanler

2. Filtreler

3. DAO Objeleri

4. Exceptionlar

5. Session Beanler

Entity Beanler, veri kaynağındaki objeleri tanımlamak için kullanılırlar. Projedeki objeleri temsil ederler.

Filtreler, entity beanlere bağlı olarak üzerlerinde sorgu oluşturmak için kullandığımız objelerdir. sorgulanacak her bir entity objesine bir filtre hazırlanması gerekir.

DAO Objeleri, veri erişim kodlarının business kodları arasına yazılıp da kodu daha kompleks ve az anlaşılır hale getirmemesi için yaratılan tekrar kullanılabilir kod katmanlarıdır.

Exceptionlar, projenin beklenen çalışma düzeninden saptığında ortaya çıkan istinai durumlardır. Projede client ve server olmak üzere iki ana başlıkta toplanmıştır.

Session Beanler, projede yapılan işleri temsil ederler ve business kodlarının bulunduğu kod katmanlarıdır. Proje boyunca yapılacak ana işler bu katmanda gerçekleşir. Burada geliştirilen kodların anlaşılır olmasına ayrıca önem verilmelidir.

Entity Beans

Entity Bean objeleri önceki EJB versiyonlarında olduğu gibi verinin saklanacağı kaynak ile ilişkilendirilmesi için kullanılmaktadır. EJB3.0 versiyonlarında annotationların kullanılmaya başlanmasıyla ve veri kaynağının çeşitli veri kaynakları yerine veritabanı ile ilişkilendirilmesi ile daha anlaşılır ve daha kolay uygulanabilir bir hale gelmiştir.

Entity Beanler bildiğimiz basit java bean objelerinin bir türevidir. Annotationlar kullanılarak veri kaynağı ile java beanler ilişkilendirilir ve Object to Relational Mapping yapısı sağlanmış olur. Hibernate ORM (Object Relaional Mapping) tool kullanılarak bu entity’ler ve ilgili varlıklar veritabanı üzerinde otomatik olarak oluşturulması sağlanabilmektedir.

Projede geliştirme yaparken entity beanlerimizi, com.acme.proje_adı.modül_adı.entity paketi altında konumlandırmaktayız.

SuperEntity

BaseEntity ve BaseEntityView class ları tarafından extend edilen soyut bir sınıftır. Entity lerde kullanılan en temel ve genel methodları barındırır. @MappedSuperClass annotation ı ile işaretlenmiştir.

BaseEntityView

Geliştireceğimiz uygulamada entity objemiz, uygulamamız tarafından yönetilmeyecek oluşturulmayacak bir view yada tablo ise yani yalnızca bilgi okuyacaksak bu tür entity beanler BaşeEntityView objesinden türetilecektir. Böylelikle türetilen objenin serializable olmasının sağlanmasının yanı sıra objenin içerisindeki alt yapı için gerekli olan id, version ve entityName değişkenleri de otomatik olarak kullanması sağlanacaktır.

BaseEntity

Geliştireceğimiz ve uygulama tarafından okunup yazılacak(CRUD işlemlerinin tümü) entity beanler BaseEntity objesinden türetilecektir. Böylelikle türetilen objenin serializable olmasının sağlanmasının yanı sıra objenin içerisindeki alt yapı için gerekli olan id, version ve entityName değişkenleri de otomatik olarak kullanması sağlanacaktır. @MappedSuperClass annotation ı ile işaretlenmiştir.

İlk Entity Bean

Entity Bean’i geliştirirken öncelikle java bean’imizi Entity Bean olarak belirten @Entity annotationini kullanmalıyız. Entity annotationin bir özelliği olarak name alanını kullanmamız özellikle önemlidir. çünkü daha sonradan kullanılacak entityleri çağırırken bu isim kullanılacaktır. Örneğin EJB/QL(yada HQL) içerisinde kullanılacak entity adını bu alan belirlemektedir. Boş bırakıldığı takdirde class ismi bu ad yerine varsayılan olarak kullanılacaktır. Projede kullanışlılığı açısından Class ismini name özelliği olarak kullanacağız.

Entity annotationından sonra veri kaynağındaki tablo adı ile ilişki kurmakta işimize yarayacak olan @Table annotationini kullanmamız gerekiyor. Bu alanın özelliği olarak tablo adını tanımlamamız gerekmektedir. Burada name için kullanılacak format büyük harfler ile (varsa-modül_kısa_adı+)entity_adı+çoğul_eki olacaktır. Örneğin entity class name:Company tablename:COMPANİES

Son olarak kullandığımız veritabanının veya alt yapının özelliklerine göre bize primary key alanı olarak kullanabileceğimiz otomatik olarak artan bir değer sunan generatorları tanımlamamız gerekmekte. Projede kullanılan veritabanı Oracle olduğundan dolayı otomatik id alan değerini sequence alt yapısını kullanarak sağlayacağız. Bunun için @SequenceGeneratör annotationini kullanacağız. Özellik olarak name ve sequenceName alanlarını tanımlamamız gerekiyor. Buradaki format hem name için hem sequenceName için büyük harf ile Entity_adı+çizgi+SEQ cümleciği olacaktır.

Eğer BaseEntityView kullanıyorsak ve kullanıma verilen datasource taki veri yapısında(table-view) belirli bir PK alanı yapısal olarak yok, birkaç alan birleştirilerek çıkartılabiliyorsa aşağıdaki gibi entity_classname_PK ismiyle bir class yaratılarak ilgili entity’de kullanılabilmektedir.

dev_help_1

Bu tanımları yaptıktan sonra JavaBeanımızın parametresiz constructorini tanımlayacağız. Constructor içerisine entityName alanı yukarıda kullanılan @Entity ile aynı değeri taşıyacak şekilde verilmelidir. Ayrıca bir collection objesi varsa bu initialize edilmelidir.

Daha sonra Entity Beanımızın hangi özellikleri taşıyacağı belirlenmelidir. Örnek olarak çalışan birisi için sicil numarası, adı, soyadı gibi alanlar private olarak tanımlandıktan sonra bir IDE aracılığı ile getter ve setter metodları yaratılmalıdır. Getterların önce yaratılması birçok uygulama sunucusu için önemlidir. Çünkü annotationlar getter methodların üzerine yazılır. (field tanımlanan alanda da yazılabilmektedir)

Getter ve setter metodlarının tanımlanmasından sonra bu alanların özelliklerini belirtmek için tekrar annotationlar yardımı ile tanımlar yapmamız gerekmektedir. Veritabanında karşılığı bulunan her alan için @Column annotationini ve bunun name özelliğini doldurmamız gerekmektedir. Kullanılacak format büyük harfler ile alan_adı olmalıdır. Karşılığı olmayacak alan için ise @Transient annotation i kullanılmalıdır.

dev_help_2

Özel Alanlar

Bazı alanlar kullanımları açısından diğerlerinden farklıdır. id alanları ve diğer entityler ile ilişki kurulan alanlar bu kapsama girerler.

Id Alani

Bir alanın primary key alanı olduğu @id annotationi ile belirtilir. @id annotationi başka bir özellik taşımaz. Bunun dışında bu alanın değerinin ne şekilde sağlandığını belirtmek için @GeneratedValue annotationi kullanılır. Bu annotatinin iki özelliği vardır. Birisi değerin ne şekilde yaratılacağını belirten strategy diğeri ise bu değeri yaratacak nesnenin belirten generatör’dir. id alanı diğer alanlar gibi @Column annotationini kullanmalıdır.

Relation Alanlari

Relation alanları bir fieldin diğer bir entity ile ilişkisini tanımlamakta kullanılır. En yaygın olanları aşağıda listelenmiştir.

Bkz => http://en.wikipedia.org/wiki/Cardinality_(data_modeling)

@OneToOne uni-bidirectional

@OneToMany uni-bidirectional

@ManyToOne uni (one-to-many bidirectional many-to-one bidirectional ile aynıdır)

@ManyToMany uni-bidirectional

Bu relationlar tanımlanırken öncelikle targetEntity ile ilişkinin kurulduğu diğer Entity classi belirtilir. Bunun dışında cascade ile entity üzerinde işlem yapıldığında diğer entitynin durumunun ne şekilde etkileneceği belirtilir. Ve son olarak fetch ile bu alanın değerinin diğer entity ile otomatik olarak doldurulup doldurulmayacağına karar verilir.

Ayrıca relation annotationlarının yanısıra diğer entity ile ilişkinin veritabanında hangi alanda tutulacağını tanımlamak için @JoinColumn kullanılır.

dev_help_3_

toString Metodu

tostring metodu ile objenin görünen değeri set edilir. Mesela çalışanların yapılacağı bir entity için return getName()+” “+getLastName() şeklinde bir tanımlama yapılabilir.

Filters

Filtreler bir entity objesine bağlı olarak çalışan ve dinamik olarak sorgu yapmaya yarayan objelerdir. Bu yüzden veri kaynağından sorgulama yapılmak istenen her bir entity objesi için buna bağlı olarak çalışabilecek bir filter objesi yaratılmalıdır.

Filtreler, *.model.filter paketi altında tutulurlar. isimlendirme formatı olarak kendisi ile ilişkilendirilen entity objesinin isminin sonuna Filter uzantısı getirilerek oluşturulur.

Filtre class ları BaseFilter objesinden türetilirler. BaseFilter constructor’ı object parametresi olarak ilişkilendirilen entity bean objesini alır. BaseFilterin sorgulama yaparken kullanılacak createQuery metodu ile sorgu oluşturulurken kullanılan isNüllOrEmpty metodu vardır. createQuery metodunda entitynin doldurulmuş alanları kontrol edilir ve bunlara göre sorgu oluşturulur.

dev_help_4

DAO Layer

DAO katmanı session beanlerin veri kaynağı ile işlemlerini gerçekleştirdikleri katmandır. session bean içerisinde yazılan business kodları ile veritabanı erişim kodlarını birbirinden ayırmak için, daha doğrusu veri kaynağına erişim kodlarını isole edebilmek için bu kodların farklı katmanlarda tutulmaları gereklidir. Bu yüzden veritabanı ile yapılan işlemler bu katman üzerinde gerçekleştirilir.

Aşağıda veritabanı üzerinde çalıştırılan modül bağımsız metodların çalıştığı dao örneği görülebilir.

dev_help_5

findByPrimaryKey id alanı atanmış herhangi bir entity objesinin veritabanından çağrılmasını sağlamaya yönelik bütün session bean objeleri tarafından kullanılabilecek bir örnektir.

Bir diğer örnek olarak getEntityList verilen entity türünden bütün objeleri veritabanından çağırarak bir collection objesinde toplar.

fındByFilter örneğinde ise verilen bir filter objesinden üretilen sorgu ve bu sorgu sonucu dönen entity objeleri business katmanına geri döndürülür.

Her modülün ortak olarak kullanabileceği metodlar için bir MainDAO objesinin yanısıra her modülün kendi işlemlerini gerçekleştirebileceği bir dao objesi bulunabilir. Örneğin EDYS projesinde ApplicationDao class ı listelerin dolmasını sağlayan, SP(StoredProcedure) çağıran metodları barındıran bir dao objesi olarak tüm Test Talep ve EDYS projelerinin istediği sorgulamaları yapmaktadır.

dev_help_6_

DAO objeleri *.model.dao paketi altinda konumlanmistir.

Exceptions

Exceptionlar program içerisinde normal çalışma akışı dışında meydana gelen durumlardır. Bu durumların elden geldiğince maksimum düzeyde kontrol edilmesi iyi bir uygulamanın özelliklerinden birisidir.

Session Beans

Entity beanler objeleri temsil ederken session beanler işlemleri temsil ederler. Bu işlemler genellikle entity beanler üzerinde yapılır. Örneğin kayıt, banka transferi, stoktan mal çıkarma gibi işlemler hep sessionbean kullanılarak yapılırlar. Her session beanın en az bir interface objesi bulunur. Bu obje sessionbean objesi ile iletişim kurmakta kullanılır. Bahsedilen interfaceler local ve remote olarak ikiye ayrılır. Local objeler aynı jvm üzerinden çağırılabilirken remote objeler dağıtılmış uygulamalarda kullanılırlar. Bu yüzden istemciler tarafından kullanılacak her metod bu interfacelerde tanımlanmalıdırlar.

Session beanler com.acme.model.sessionbean paketi altında bulunurlar.

Session bean tanımlanırken öncelikle session beanın tipi belirtilir. Projede kullanacağımız session bean türü stateless session beanlerdir. @Stateless annotationi beanımızın stateless olduğunu belirtmede kullanılır. Ayrıca veritabanı ile yapılacak transactionları containerin yönetmesini sağlamak için @TransactionManagement annotationi kullanılır ve tipi de CONTAiNER olarak belirtilir. Ayrıca performans ve log tutmak için alt yapı tarafından kullanılan interceptorlar da @Interceptors annotationi kullanılarak sessionbeane tanımlanır.

Bu tanımları yaptıktan sonra beane default erişim seviyesini de beanı geliştirmeye başlamadan önce verebiliriz. Bu seviye bütün metodlar için geçerli olacaktır.

Stateless session beanler ile ilgili önemli bir konuda adından da anlaşılabileceği gibi bu beanler client ile ilişkili durum bilgilerini tutmazlar. Bu yüzden işlem yaparken herhangi bir durumlarını scope’u metod dışında olan bir değişkende tutup kontrol etmek veri tutarsızlığına kadar giden sorunlara yol açabilecektir.

Session beanımızı geliştirirken ilk yapmamız gerekenlerden birisi ORM ile ilişkiyi yönetecek olan EntityManageri tanımlamaktır. Bu objeyi tanımlarken hangi persistence context(entity objelerini tutan alan) ile ilişkisi olacağını @PersistenceContext annotationi ile yapabiliriz. Bu annotationa özellik olarak ünitName tanımlanır ve buraya verilecek değer persistence.xml dosyası içerisinde bulunur.

Constructorda bean içerisinde ortak olarak kullanılacak daolar initialize edilir.

Interface te tanımlı metodlarda metoda girmeden önce @RolesAllowed ile yetki seviyesi rol bazında belirlenmelidir. Default olarak classta tanımlanan role geçerli olacaktır. Birden fazla role yetki verilebilir.

EntityManager ile transactional işlemler yapmadan önce veri tutarlılığı açısından EntityManager’in flush modu COMMiT olarak atanmalıdır.

Bilinmesi gereken bir diğer obje de serverResponse’ tur. serverResponse içerisinde hem data hem de client tarafından işlenebilecek kontrol edilmiş exceptionları barındıran bir sınıftır. Özellikle işlem yapıldığı takdirde uyarı çıkabilecek durumlarda kullanılmalıdır.

Bunlar;

  • synchronizeEntities(GridData gridData) throws Exception

· refreshEntities(serverResponse response, Collection entityList)

  • persistEntities(serverResponse response, Collection entityList)
  • removeEntities(serverResponse response, Collection entityList)

synchronizeEntities client tarafında grid üzerinde tutulan datanın son halinin veritabanına yazılması için kullanılan metoddur. Grid içerisindeki data ile tek tek işlem yapar ve kontrol dahilinde olan bir exception oluştuğunda bunu response içerisine ekler ve diğer datalar üzerinde işlem yapmaya devam eder.

synchronizeEntities metodu kullanılırken dikkat edilmesi gereken bu metoda gönderilen griddeki dataların birbirleri ile bağlantısının ne şekilde olacağıdır. Örnek olarak grid self reference olan entity objelerini tutuyorsa veri tutarlılığı açısından kullanılan metod değiştirilmelidir.

refreshEntities metodu veritabanından son halleri çekilecek olan entitiylerin response objesi olarak geri döndürülmesi için kullanılan metoddur.

persistEntities ve removeEntities te refreshEntities metodu gibi entityList içerisinde bulunan entitylerin veritabanına kaydedilmesi ve silinmesi işlemlerini yaparlar ve yanıtları response objesinde tutarlar.

Development

EJB bean ler JNDİ üzerinden structure projesi altındaki ServiceLocator objesi ile çağrılır. JNDI a kaydolabilmesi için Model projesi içerisinde ilgili xml file da gerekli tanımlamalar yapılmalıdır.

Deployment kütüphanelerinin önceliği ise weblogic-application.xml dosyasında belirtilir.

dev_help_7

Sıradan bir tanımlama ekranı geliştirirken izlenebilecek sıra şu şekilde olabilir.

• Server tarafında geliştirme yaparken öncelikle entitylerin tanımlanması mantıklı olur. Entityler hem server hem client tarafında kullanılacak temel objelerdir.

• Entity tanımlandıktan sonra eğer bu entity objesi üzerinde sorgulama yapılacaksa filtre tanımlanmalıdır.

• Bu işlemden sonra gerekli dao metodlarının tanımlanması gerekir. Bu adım her zaman gerekmeyebilir veya sessionbeanler geliştirilirken dao metodları aynı zamanda geliştirilebilir.

• Bu adımda exceptionların tanımlanması gerekir. Business exceptionlar yalnızca ve yalnızca sessionbeanler üzerinden atılmalıdır.

• Exceptionların ardından business işlemlerinin gerçekleştiği session beanlerin ve interfacelerin tanımlanması gelir. sessionbeanler yukarıda bahsedilen adımlarda geliştirilen tüm objeleri kullanabilirler bu yüzden en son veya 3. ve 4. adımla birlikte tanımlanmaları gerekir. session beanden önce interface objesinin tanımı yapılmalıdır. interface objesinin metodları önce session bean objesinde tanımlanır.

Business işlemleri gerçekleştirilirken ise

• Entity beanler genellikle önceden yaratılmış olacaktır.

• Filtre objeleri muhtemelen gerekmeyecektir veya önceden tanımlı olacaktır.

• Muhtemelen önceden hazırlanmış dao metodları kullanılacaktır(fındByPrimaryKey, fındByFilter gibi).

• Business işlemleri yapılırken oluşacak istisnai durumlar göz önüne alınıp bu durumlara uygun exceptionların oluşturulması gerekir.

• Business işlemleri gerçekleştirecek sessionbeanler ve interfaceleri hazırlanır. Gerekiyor ise weblogic-ejb-jar.xml dosyasına tanımlanırlar.

Bu işlemlerden sonra model projesi deploy edilmeye hazır hale gelmiş olacaktır.

Resources

Java uygulamalarında statik olarak hazırlanan textlerin yerel dillere çevrilmesi için kullanılan en yaygın metod resource bundleları kullanmaktır. Resource Bundle’lar bir anahtar sözcüğün karşılığı olarak bir obje döndüren dizilerdir.

Çoğu java uygulaması gibi bu uygulamada da bu iş için Resource Bundle’lar kullanılmaktadır. Altyapı ve her modül için ayrı birer resource bundle tanımlanmıştır. ResourceBundle’lar ListResourceBundle objesinden türemişlerdir.

Component etiketleri, exception tanımları, genel mesajlar(lütfen bekleyiniz, işlem başarılı veya konfirmasyon işlemleri gibi), veya modül bağımsız genel ekranlar(login, logout, şifre değişimi) gibi işlemler alt yapı için kullanılan resource bundle içinde tanımlanabilirler. Resource Bundle’lar; Resources projesi altindaki com.arsivist.resource.bundle paketi altinda bulundurulurlar.

İsimlendirme olarak da ResourceBundle+”_”+varsa-modul_adi+”_”+local_dil_kodu verilebilir.dev_help_8_

ViewController projesi Geliştirme

Oracle ADF ile Web uygulamaları , masaüstü uygulamaları, mobil uygulamalar; JDeveloper geliştirme ortamının sunduğu deklaratif yöntemlerle ve görsel arayüz desteğiyle kolaylıkla oluşturulabiliyor.

Model: İş mantığı (Business Logic) bölümüdür. Tek katmandan oluşabileceği gibi, birden fazla katmanı da içinde barındırabilir. Tek katmandan oluştuğunda genelde veritabanına kayıt ekleme, kayıt çekme, kayıt silme vb. veritabanı işlemleri için kullanılır. Controller’den gelen değerleri işler ve geriye döndürür. Model katmanında herhangi bir –loglama haricinde- output işlemi yapılmaz.

View: Uygulamanın kullanıcıya gösterilen arayüzünün bulunduğu katmandır. Html, Css, Javascript, JSF vb. bu katmanda bulunur.

Controller: Uygulamanın karar mekanizmasıdır. Model ile View arasında köprü görevi görür.

İş Servisleri Katmanı: Bu katman farklı kaynaklardaki veriye erişimin sağlandığı ve iş mantığının tanımlandığı katmandır.

Bu katmanların tümünde, Oracle ADF istenilen teknolojinin kullanılmasına olanak sağlar. EJB, örneğin iş servisleri katmanında Web servisleri, JavaBeans, JPA, Hibernate kullanılabilirken, View katmanında, JSF, JSP, ADF Faces kullanılabilir. Sektördeki uygulama sunucularından biri olan WebLogic JDeveloper ile entegre olarak paketlenmiş halde gelmektedir. JDeveloper ve ADF ile uygulamanızı geliştirirken, aynı anda WebLogic üzerinde test/debug yapılabilmektedir.

MVC tasarım deseni temel alan Oracle ADF framework unde UI tarafında JavaServerFaces standardının üstüne konumlandırılan ADFFaces kullanılarak UI bileşenleri tasarlanır, UI bileşenleriyle model tarafını konuşturan Contoller’lar (MBean classları) aynı projede geliştirilebilmektedir(ViewController projesi). MBean ler gibi java objeleri src nin altında *.vc.projectname hiyerarşisindeki gibi bir paket yapısıyla yer alırken html bileşenleri ve taşk-flow konfigürasyon dosyaları public_html klasörünün altında yer bulur.

Basit bir fonksiyonel ekran düşünelim. Önyüzde son kullanıcıya bazı UI bileşenleri gösterilecek, girilen yada otomatik yüklenen bazı bilgilere göre kullanıcıya bazı bilgiler gösterilecek. Bu durumda öncelikle aklımıza hangi bilgilerin ne şekilde getirilerek gösterileceği aklımıza gelmektedir. Veri kaynağını sağlayacak business service bir webservisi, web’e açık bir api, bir ADFBC datacontrol bileşeni, EJB nesnesi olabilir. Bu service nesneleri, veritabanından, BPM’den yada yalnızca memorydeki bir pojo objesinden veri getiriyor olabilir. Veri getirilen katman ve kontrolörleri model katmanı olarak düşünebiliriz. Bu kısmı tamamladığımızı düşünürsek ön tarafta kullanıcının neleri nasıl göreceğini ve nasıl kontrol edeceğini düşünmeye geçeriz. Bu aşamadaki çözüm Controller katmanıdır; ADF frameworkundeki karşılığı ise taskflowlar olabilmektedir.

Task-flow da kullanılacak (ManagedBean)MBean ler task-flow larda tanımlanarak on yüzden tetiklenmesi yada önyüzü oluşturulması sağlanır. MBean ler ise Model projesi ve diğer util projelerine ulaşarak task-flow un ihtiyaç duyduğu verileri kaydedip sağlayarak hizmet verir, WebService çağırarak süreç tetikler, UCM den doküman çeker yada revizyonlar… Contoller objeleri; View katmanından gelen istekleri(request) model’e gönderir ve Model katmanından aldığı verileri view’e aktarır.

Oluşturulan task-flow yapısı xml dosyaları ile file systemde tutulmaktadır. Task-flow bileşenlerine özgü bileşen palette inden view bileşenini eklersek. Bu bileşenin karşılığı olarak bir web sayfası(jsp, jspx, jsf, jsff) yaratacağız demektir. Sayfaya, ihtiyacımız olan UI bileşenlerini ekleyerek task-flowda tanımladığımız MBean class ındaki ilgili metotlarla bağlantısını kurarız(binding). Task-flow üzerinde tanımlanan sayfa ve metot çağrımları sırasında ise veri geçişlerini çağıracak parametre leri tanımlarız.

Uygulamayı portal uygulaması olarak planladıysak oluşturulan task -flow lar bir jspx dosyasına atılarak geliştirme sırasında integrated weblogic sunucusu üzerinde çalışması gözlemlenir. Her bir ön yüz bileşeni esasında jsff fragment i olarak tasarlanabilmektedir. Her bir fragment ise istenilen –yapısına uygun olmak koşulu ile- bir task-flow içerisinde bir view bileşenine denk gelecek biçimde kullanılabilmektedir.

dev_help_9

firewall_kullanim

Engellenmemiş Traceroute Komutu

Windows sitemlerde bir sayfaya ya da sunucuya veri sağlayan tüm sunucuların adreslerini çıkarmaya yarayan komut tracert komutudur.

Windows işletim sitemi üzerinde yapılmış basit bir traceroute örneği örneği aşağıda ekran görüntüleri ile açıklanmıştır. Herhangi bir firewall engellemesi olmadığı için komut sağlıklı çalışmaktadır.

1) “Start > Run” veya “Windows Tuşu+R 2) Açılan ekrana “cmd” yazıp “Enter” basın bu bizi DOS komut satırına götürecektir. 3) Komut satırına “tracert www.yandex.com.tr” yazıp enter’ a basın 4) Karşınızdaki ekranda verinin gidişini izleyebilirsiniz

Örnekte hostname olarak www.yandex.com.tr adresi verilmiştir. Bu adres yerine ip bilgisi de yazılarak da paketler kontrol edilebilir. Aşağıdaki ekran görüntüsünde paketlerin ne kadar süre içinde karşılık veridiğini ve ip kaynak yönlendirme seçeneğinin hangisi olduğunu görebilirsiniz.cmdPrmpt1

Traceroute IP başlığındaki TTL (Time To Live- Yaşam Süresi) alanını ve ICMP (Internet Control Message Protocol – İnternet Kontrol Mesaj İletim Kuralı) kullanır. Ekran görüntüsündeki ms cinsindeki üç değer, o TTL değeri ile gönderilen üç veri paketinin, icmp mesajının gelişine kadar gecen sürelerdir. Sistemin sağlıklı çalışması için hedefte bir UDP modülü olması yeterlidir.

Traceroute yapılmasını Windows firewall kullanarak engelleme

Windows üzerinde aşağıdaki gibi basit bir giden firewall kuralı tanımlayarak UDP’ye olan erişimi engelleyebiliriz.

İzlenmesi gereken yol:

Başlat > Denetim Masası > Windows Güvenlik Duvarı > Gelişmiş Ayarlar > Giden Kuralları > Yeni KuralcmdPrmpt2

Aşağıda windowsun kendi sihirbazlarını kullanarak oluşturduğumuz “cemip” adlı giden kuralı sayesinde yandex.com.tr adresine yapılan tracert komutunun sonucunu görebilirsiniz.firewall_result

Konsol uygulamamızda Windows firewall iletişimi kestiği için “Hedef sistem ismi çözümlenemedi” sonucu alınmaktadır.cmdPrmpt4

Dünyada kullanılan iş zekası çözümlerinden ticari olarak en kabul görenlerinden birine Oracle BI ürününü örnek gösterilebilir. Oracle firması RDBMS veritabanlarının en güvenilir kendini kanıtlamış olanı ile uzun süre bilgi teknolojileri çevresinin duyulan ve bilinen ismiydi. Sun’ı ve piyasadaki daha nice OpenSource ürünleri satın alarak bir koldan açık kaynak kullanım paketini desteklerken diğer koldan bu ürünlerin üzerine kendi ticari paketlerini inşa etmektedir. ( aklıma gelen örnekler şöyle sıralanabilir: BEA->Weblogic, AqualogicBPM->OracleBPM…) Yoğun data, veri madenciliği, istatistik ve raporlama gibi konuları içeren İş Zekası çözüm araçlarından birinin veritabanı ile ünlü bir firma tarafından da geliştirilmiş olması bu açıdan şaşırtıcı görünmemektedir.

Oracle BI Enterprise Edition ürünleri BI yetenekleri açısında oldukça geniş bir yelpaze sunmaktadırlar. İnteraktif gösterge panelleri, ad-hoc analizleri, proaktif uyarılar, gerçek zamanlı tahminleme olanakları, kurumsal ve finansal raporlamalar bunlar arasında sayılabilir.

OLAP (Online Analytical Processing) OLAP çevrimiçi analitik işleme için bir kısaltmadır. İş zekası için arama iş verilerini analiz etmek için bilgisayar tabanlı bir tekniktir. OLAP küpü, kendi boyutları içinde anlaşılabilir 1 yada daha fazla boyutlu veri dizisidir.

Kaynak: http://en.wikipedia.org/wiki/OLAP_cube

OLAP

Oracle OLAP Oracle 11g veritabanı ile entegre olan ,firmalara kolayca bir iç bakış ve kavrama ile iş performansı kazanımını amaçlayan bir bileşendir.

· Harici sorgu, hesaplama ve farklı küplerle harmanlanarak daha kapsamlı yada anlamlı olabilecek raporlamalar yapabilme,

  • Zengin analitik yetenekler,

· İşi yapan kullanıcılara (örneğin bütçe uzmanı, mali işler uzmanı…) sürekli IT desteği ile ilerlemek yerine kendi raporlamalarını kendileri tasarlayarak raporlayabilecekleri ortam.

  • Yine tüm SQL araçlarınca özgürce erişim imkanı

gibi yetenekler sunulmaktadır.

Oracle BI OLAP

Oracle 11g veritabanı OLAP opsiyonu ile birlikte kurulur. 11.1.1.0.8.7 yada yukarısı olmalıdır. Analitik Çalışma Ortam Yöneticisi (AWM de bu kurulumda işaretlenmelidir)

Kurulum yada kullanımdaki açık konular yada geliştirilmesi düşünülen konular OTN foruma yazılarak destek aranabilir. Yada ticari lisansa sahip olunursa Oracle’dan direk destek istenebilir.

Yerel çokboyutlu nesne tipleri OLAP küplerince desteklenmektedirler. Küpler, Ölçümler(Measures) ile oluşturulup Boyutlar(Dimensions) ile düzenlenirler.

Measures , Sayış, Maliyet, Kar gibi gerçek verileri sunar. Bu veriler veritabanında belli aralıklarla hesaplanarak saklanıp isteğe göre hızlı bir şekile buradan üretilir yada anlık sorgulama zamanında her seferinde hesaplanarak hizmete sunulur. Ölçümler veritabanında saklanıp buradan yüklenir. Ortak hesaplamalarla oranlar, farklar, zaman serileri gibi datalar elde edilir. Hesaplamalar için disk alanına ihtiyaç duyulmaz.

Dimensions, ölçüm datalarını(Measures) tanımlar ve sınıflandırır . Ölçüm datalarının oluşturduğu noktalar forma sokularak kenarlar oluşturulur. Boyut hiyerarşileri isteğe bağlıdır ancak OLAP sistemlerde yaygındır. Bir hiyerarşi bu analiz amacıyla birlikte boyut üyeleri gibi mantıksal bir yapıdır. Bir boyutun yapısı, ebeveyn-çocuk ilişkilerine dayalı hiyerarşik olarak düzenlenir. Bu ilişkiler, çocuk değerlerden üst değerlere düzeyleri arasında gezinme işlemlerini sağlar.

Cubes, benzer verileri aynı boyutta toplamak için uygun bir yol sağlamaktadır. Elbette ki tüm veriler ayn şekle sahip değiller, ayrıca her veriyi kendine uygun şekillendirmek de akıllıca değil. İşte bu noktada OLAP veri modelini çıkartabilmek için küplere ihtiyaç duyulacak. Küpler, benzer verileri doğru boyutlar altında tutmaya yarayacaktır.

BI tool unu Yönetim Kurulu ve Genel Müdür lerin hızlıca raporlamalara ulaşabilmeleri, bütçe planlamaları ve stratejik kararları verebilmeleri için Kokpit projesinde kullanılması amaçlanmıştır. Geliştirdiğim uygulamanın ürettiği veriler de proje kapsamında bulunduğundan küp üzerinde olması gerekmektedir.

Öncelikle, bu verileri çekecek ve küplere doğru şekilde yerleştirebilmek için verinizin ve veri yapinizin anlaşılır, tutarlı olması çok büyük önem taşımaktadır. Veritabanında tablolarda PK – FK yapısının kuvvetli ve standardizasyonlarla constraint lerin düzgün yapılandırılmış olması beklenmektedir. Uygulama geliştirme ekibi olarak BI uzmanlarının istediği formata uygun biçimde veri sağlayacak sorgu view ları hazırlanır, küplere bu sorguların kullanılması anlatılır ve veri tutarsızlığı varsa bu import tan önce kontrol edilmelidir. Bu sebeple şunu belirtmekte fayda var ki BI araçlarının kurulumundan önce düzgün verilerin hazırlanması önemlidir, aksi halde ilerlemek mümkün olmayacaktır.

Kullanılan IDE: Oracle Jdeveloper 11.1.1.6

Kullanılan JDK: 1.6.0_30

Kullanılan RDBMS : MySQL 5.6 vs Kullanılan NoSQL: MongoDB 2.4.8

Kullanılan DB bağlantı arayüzü: JDBC

DB ler lokalde kuruludur. Network trafiği göz ardı edilebilir.

Test senaryosu: Aynı PC ile aynı field sayısı kadar bir tablo oluşturarak istenilen aynı sayıda kaydı yaratmak sonra da aynı koşul ile çekmek.

Özet sonuç: NoSQL veritabanı genel olarak çok daha hızlı görülüyor. Yalnız fetch işleminde RDBMS in daha hızlı olduğu görülüyor.

Ancak NoSQL veritabanları için göze çarpan dezavantajın ilişkisel tablolardan (collection) bir arada veri çekilmesi işlemindeki zorluk ve yavaşlık olduğu söylenmektedirBu nedenle bir de rdbms sistemde join ile çekilen query ler üzerinden kıyasa gitmek daha kesin yorum yapabilmek için anlamlı olacaktır.

Benchmark çalışmasında 1Milyon kayıt içerisinden 50bin adet döndüren bir sorgu yapılıp fetch edilmiştir.

MySQL:

totalTime of insert operation: 983 (saniye)

First Select time: 913 ms

First Fetch time of select operation in ms: 32

Second Select time: 845 ms

Second Fetch time of select operation in ms: 33

MongoDB:

totalTime of insert operation : 222 (saniye)

First Select time: 2 ms

First Fetch time of select operation in ms: 1323

Second Select time: 1 ms

Second Fetch time of select operation in ms: 1503

Rows of select count: 50000 (for both test)

Jdev projesi istenirse buradan indirilebilir. (password: ybs123)

Benchmark projesinin source kodları:

package com.benchmark;

import com.benchmark.util.DateUtility;

import com.mysql.jdbc.Connection;

import com.mysql.jdbc.Statement;

import java.sql.DriverManager;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.Random;

import java.util.UUID;

public class MySQL

{

private Connection con;

public static void main(String[] args)

{

new MySQL();

}

public MySQL()

{

try

{

connect();

createTable();

insertBenchmarkVeri();

selectTest();

}

catch (Exception e)

{

e.printStackTrace();

}

}

private void connect()

{

try

{

Class.forName(“com.mysql.jdbc.Driver”).newInstance();

con = (Connection)DriverManager.getConnection(“jdbc:mysql://localhost:3306/” + “test”, “root”, “admin”);

}

catch (Exception e)

{

e.printStackTrace();

}

}

private void createTable() throws SQLException

{

try

{

con.createStatement().execute(“DROP TABLE test”);

con.createStatement().execute(“CREATE TABLE test ” + “(id INTEGER not NULL AUTO_INCREMENT, ” + ” test1 VARCHAR(255), ” +

” test2 VARCHAR(255), ” + ” test3 VARCHAR(255), ” + ” test4 INTEGER, ” + ” PRIMARY KEY ( id ))”);

}

catch (SQLException e)

{

e.printStackTrace();

con.close();

}

}

private void insertBenchmarkVeri()

{

final Statement st;

try

{

st = (Statement)con.createStatement();

Random generator = new Random();

String c, d, e;

int x = 0;

int ayniKayitLimit = 50000; // select yapildiginda donecek kayit sayisi

int nrCount = 0;

long startTime, totalTime;

startTime = System.currentTimeMillis();

System.out.println(“startTime for insert operation in ms: “+startTime);

for (int i = 0; i < 1000000; i++)

{

if (i % 250000 == 0)

{

System.gc();

}

final String randomString = UUID.randomUUID().toString();

c = randomString.substring(0, 5);

d = randomString.substring(5, 10);

e = randomString.substring(10, 15);

if (ayniKayitLimit >= nrCount)

{

nrCount++;

st.execute(“INSERT INTO `test` (`test1`, `test2`, `test3`, `test4`) VALUES (‘” + c + “‘, ‘” + d + “‘, ‘” + e + “‘, 12345)”);

} else

{

x = generator.nextInt(9999);

st.execute(“INSERT INTO `test` (`test1`, `test2`, `test3`, `test4`) VALUES (‘” + c + “‘, ‘” + d + “‘, ‘” + e + “‘, ‘” + x + “‘)”);

}

}

totalTime = DateUtility.getSecondsBetween(startTime, System.currentTimeMillis());

System.out.println(“totalTime of insert operation in second: “+totalTime);

}

catch (SQLException e)

{

e.printStackTrace();

}

}

private void selectTest()

{

ResultSet res;

long startTime, totalTime;

Statement st;

try

{

st = (Statement)con.createStatement();

startTime = System.currentTimeMillis();

res = st.executeQuery(“SELECT * FROM test WHERE `test4`=12345”);

totalTime = System.currentTimeMillis() – startTime;

System.out.println(“Select time: ” + totalTime + ” ms”);

startTime = System.currentTimeMillis();

int count = 0;

while (res.next())

{

count++;

}

totalTime = DateUtility.getSecondsBetween(startTime, System.currentTimeMillis());

System.out.println(“Fetch time of select operation in second: “+totalTime);

System.out.println(“Rows of select count: ” + count);

}

catch (Exception e)

{

e.printStackTrace();

}

}

}

package com.benchmark;

import com.benchmark.util.DateUtility;

import com.mongodb.BasicDBObject;

import com.mongodb.DB;

import com.mongodb.DBCollection;

import com.mongodb.DBCursor;

import com.mongodb.MongoClient;

import java.sql.SQLException;

import java.util.Random;

import java.util.UUID;

public class Mongo

{

private DB db;

private DBCollection collection;

MongoClient mongoClient;

public static void main(String[] args)

{

new Mongo();

}

public Mongo()

{

connect();

selectTest();

}

private void connect()

{

try

{

// To connect to mongodb server

mongoClient = new MongoClient(“localhost”, 27017);

// Now connect to your databases

db = mongoClient.getDB(“test”);

System.out.println(“Connected to database successfully”); //Connected to db, if db is not exist, would be created automatically.

// boolean auth = db.authenticate(“mustafa”, “benchmark”.toCharArray());

// System.out.println(“Authentication: ” + auth);

}

catch (Exception e)

{

System.err.println(e.getClass().getName() + “: ” + e.getMessage());

}

}

private void createTable()

{

try

{

db.getCollection(“test”).drop();

collection = db.getCollection(“test”);

System.out.println(“Collection created successfully”);

}

catch (Exception e)

{

e.printStackTrace();

}

}

private void insertBenchmarkVeri()

{

int x = 0;

BasicDBObject document;

Random generator = new Random();

String c, d, e;

int ayniKayitLimit = 50000; // select yapildiginda donecek kayit sayisi

int nrCount = 0;

long startTime, totalTime;

try

{

startTime = System.currentTimeMillis();

System.out.println(“startTime for insert operation in ms: ” + startTime + ” sys date: ” + DateUtility.getToday());

for (int i = 0; i < 1000000; i++)

{

if (i % 10000 == 0)

{

System.gc();

}

final String randomString = UUID.randomUUID().toString();

c = randomString.substring(0, 5);

d = randomString.substring(5, 10);

e = randomString.substring(10, 15);

if (ayniKayitLimit >= nrCount)

{

nrCount++;

document = new BasicDBObject();

document.put(“test1”, “” + c + “”);

document.put(“test2”, “” + d + “”);

document.put(“test3”, “” + e + “”);

document.put(“test4”, 12345);

collection.insert(document);

} else

{

x = generator.nextInt(9999);

document = new BasicDBObject();

document.put(“test1”, “” + c + “”);

document.put(“test2”, “” + d + “”);

document.put(“test3”, “” + e + “”);

document.put(“test4”, “” + x + “”);

collection.insert(document);

}

}

totalTime = DateUtility.getSecondsBetween(startTime, System.currentTimeMillis());

System.out.println(“totalTime of insert operation in second: ” + totalTime);

}

catch (Exception exc)

{

exc.printStackTrace();

}

}

private void selectTest()

{

long startTime, totalTime;

try

{

collection = db.getCollection(“test”);

BasicDBObject query;

DBCursor cursor;

query = new BasicDBObject();

query.put(“test4”, 12345);

startTime = System.currentTimeMillis();

cursor = collection.find(query);

totalTime = System.currentTimeMillis() – startTime;

System.out.println(“Select time: ” + totalTime + ” ms”);

startTime = System.currentTimeMillis();

int count = 0;

while (cursor.hasNext())

{

count++;

cursor.next();

}

totalTime = System.currentTimeMillis() – startTime;

System.out.println(“Fetch time of select operation in ms: ” + totalTime);

System.out.println(“Rows of select count: ” + count);

}

catch (Exception exc)

{

exc.printStackTrace();

}

}

}

Özcan Acar Hoca’nın Spring üzerine kitabı oldukça faydalı. Kendisinin sitesinde promote ettiği bir bölümünü burada bulabilrsiniz.

Spring İle Tanışalım

Bir Program Nasıl Oluşur?

Spring’in detaylarına girmeden önce, bir programın oluşum hikayesine göz atmamızda fayda var. Bir programm oluşumundaki yön verici en önemli etken, programı kullanacak olan müşterinin iş piyasasındaki gereksinimleridir. Program müşterinin iş hayatını kolaylaştırmak, firma bünyesindeki aktiviteleri organize etmek ve kazanç sağlamak için kullanılır. Yazılım esnasında müşteri tarafından oluşturulan kriterlerin dikkate almması gerekmektedir, aksi taktirde müşterinin isteklerini karşılayamayan ve günlük iş hayatında kullanılamaz bir program ortaya çıkar.

Yazılım süreci müşteri isteklerinin analizi ile başlar. Analiz safhasında müşterinin gereksinimleri tespit edilir ve yazılım için gerekli taban oluşturulur. Analiz ve bunu takip eden yazılım, müşteri isteklerinin transformasyona uğradığı ve netice olarak bir programm oluşturulduğu karmaşık bir süreçtir.

Program

Resim2.1 Resim 2.1

Transformasyon müşteri gereksinimlerinin tespiti ile başlar. Sadece müşteri ne istediğini bilebilir ve programcı olarak bizim görevimiz, müşterinin istekleri doğrultusunda programı şekillendirmektir. Şimdi bu sürecin nasıl işlediğini bir örnek üzerinde birlikte inceleyelim. Hayali bir müşterimiz bizden sahip olduğu araç kiralama servisini yönetmek için bir yazılım sistemi oluşturmamızı istiyor. Kitabı oluşturan bundan sonraki bölümlerin hepsinde araç kiralama servisini bölüm konusuna uygun olacak şekilde Spring çatışmı kullanarak geliştireceğiz. Vereceğim tüm örnekler bu uygulamadan alıntıdır ve kodlar her bölüm için hazırladığım Maven projesinde yer almaktadır. Bu projeleri Edipse altmda kullanabilirsiniz.

Araç Kiralama Servisi

Spring’in nasıl kullanıldığını göstermek amacıyla bu bölümden itibaren hayali bir araç kiralama servisi için gerekli yazılım sistemini oluşturmaya başlayacağız.

Bu yazılım sistemi aracılığı ile müşteriler internet üzerinden rezervasyon ve kiralama işlemlerini yapabilecekler.

Program Alan Modeli (Domain Model)

Müşteri gereksinimlerini program koduna dönüştürebilmemiz için bir model oluşturmamız gerekiyor. Bu modelden yola çıkarak neyin nasıl programlanması gerektiğini daha iyi anlayabileceğiz ve yazılım sürecine yön vereceğiz. Yazılımda bu tür modellere alan modeli (domain model) ismi verilmektedir. Alan ile, programın kapsadığı çalışma alanını kastedilmektedir. Araç kiralama servisi örneğinde içinde bulunduğumuz alan araç kiralama servisinin çalışma sahasıdır.

Alan modelinde çalışma sahasında kullanılan birimler, bu birimlerin rolleri ve birbirleriyle olan ilişkileri yer alır. Bu birimler çalışma sahasma has kullanılan terminolojiden türetilir. Bir araç kiralama servisinde çalışan personelin aralarında yaptıkları konuşmalara kulak verdiğinizde araba, müşteri, rezervasyon, ödeme, adres, rezervasyon iptali gibi bu çalışma sahasma has terimler duyarsınız. Bu terimler genelde oluşturulan alan modelinde yer alan birimlerdir. Müşterinin sahip olduğu gereksinimleri tespit edebilmek için yazılım ekibi tarafmdan gerekli soruların sorularak, çalışma sahasmda yer alan birimlerin ortaya çıkarılması gerekmektedir.

Yazılım sistemleri için alan modelleri UML (Unified Modeling Language) olarak isimlendirilen bir modelleme dili ile yapılır. Aşağıda araba kiralama servisi için oluşturduğumuz alan modeli yer almaktadır.

Resim2.2 Resim 2.2

Resim 2.2 de yer alan alan modelinde birimler arası bağlantılar olduğu görülmektedir. Bu bağlantılar iki birim arasındaki interaksiyonu tanımlamak için kullanılmaktadır. Birimler birbirlerini kullanarak, modelledikleri verilerin kullanım ve işlenme tarzlarmı belirlerler.

Sınıflar arası ilişkilerin derecesini belirtmek için rakamlar kullanıyoruz. Kullanılan rakamlar şu şekildedir:

0,1

Sınıf karşı sınıf tarafından ya hiç kullanılmamaktadır ya da en fazla bir kez kullanılmaktadır.

0..*

Sınıf karşı sınıf tarafından ya hiç kullanılmamaktadır ya da birçok kez kullanılmaktadır.

1,1

Sınıf karşı smıf tarafından ya en az bir kez ya da en fazla bir kere kullanılmaktadır.

1..*

Sınıf karşı sınıf tarafından ya en az bir kez ya da birçok kez kullanılmaktadır.

Şimdi bu şemayı kullanarak araç kiralama servisi alan modelinde yer alan nesne ilişkilerine bir göz atalım.

Bir müşteriyi temsil eden Customer ile bir araç kiralama işlemini temsil eden Rental arasında 1-0* ilişkisi vardır. Buna göre bir müşteri sıfır ya da birden fazla araç kiralamış olabilir ve her bir araç kiralama işlemi sadece bir müşteri için yapılmıştır.

Rental ve kiralanan aracı temsil edenCar arasında 0,*-1 ilişkisi vardır. Buna göre bir araç kiralama işleminde (Rental) sadece bir araç kiralık olarak verilebilir. Buna karşın bir araç sıfır ya da birden fazla müşteri için kiraya verilmiş olabilir.

Bir müşteri rezervasyonunu temsil eden Reservation ile Customer arasında 0,*-1 ilişkisi mevcuttur. Bu bir rezervasyonun sadece bir müşteriye ait olduğunu, bir müşterinin sıfır ya da birden fazla rezervasyonu olabileceği anlamına gelmektedir.

Müşteri tarafından yapılan ödemeyi temsil eden Payment ile Customer arasında 1 ,*-1 ilişkisi bulunmaktadır. Bu yapılan bir ödemenin bir müşteriye ait olduğu, bir müşterinin en az bir ya da daha fazla ödemesi bulunduğuna işaret etmektedir.

Müşterinin adresini temsil eden Address ile Customer arasında 1-1,* ilişkisi bulunmaktadır. Bu her müşterinin en az bir adresi olması gerektiği, her adresin mutlaka bir müşteriyi ait olduğu anlamına gelmektedir.

Spring ile geliştireceğimiz uygulamada alan modelinde yer alan birimlerin hepsini birer Java sınıfı olarak implemente edeceğiz. Bu tür sınıflara yazılımda entity (öğe) ismi verilmektedir. Bu öğeler aracılığı ile uygulama bünyesinde kullanılan verileri modelleyebiliriz. Bir Customer öğesi örneğin bir müşteriyi temsil eden tüm özellikleri ihtiva eder. Bu öğelerin Java gibi nesneye yönelik bir programlama dilinde sınıf olarak kodlanmaları, yazılımcının öğeler arasındaki ilişkileri daha iyi anlamasını sağlamaktadır.

Bir uygulama sadece alan modelinde yer alan entity nesnelerinden oluşmaz. Alan modeli veri yapılarını modellemek için kullanılır. Asıl uygulama bu verileri üzerinden işlem gerçekleştiren yazılım yapısıdır. Veriler üzerinde yapılan işlemleri ve program akışını daha iyi kavramak için dizge diyagramları oluşturabiliriz. Dizge diyagramları hangi kod birimlerinin hangi işten sorumlu olduğunu gösterirler. Bu şekilde uygulamanın hangi parçalardan oluştuğunu anlamak ve parçaları geliştirmek kolaylaşır.

Dizge Diyagramı (Sequence Diagram)

Kod yazmadan önce program akışını görselleştirmek için kullanabileceğimiz diğer bir araç ta UML dizge diyagramlarıdır. Resim 2.3 de bir araç kiralama işlemi için yapılması gereken işlemler yer almaktadır. RentalService, CustomerRepository ve RentalRespository diyagram bünyesinde kullandığımız Java sınıflarıdır. Bu diyagram bünyesinde hangi sınıfın hangi metodu çağırarak, işlem yaptığı yer almaktadır.

Resim2.3 Resim 2.3

İlk Çözüm

Spring kullanmadan araç kirala servisi uygulamasmı nasıl geliştirirdik? Bu sorunun cevabmı aramaya koyulmadan önce bir birim testi yazalım. Bu birim testi bize uygulamanın geliştirilmesinde yol gösterici nitelikte olacaktır. Yeni bir kiralama işlemini test eden birim testi kod 2.1 de yer almaktadır.

Kod 2.1 – RentalServiceTest

package com.kurumsaljava.com.spring;

import static junit.framework.Assert.assertTrue;

import j ava.text.SimpleDateFormat;<br/> import java.util.Date;<br/> import org. j unit. Test; <br/x/code>

public class RentalServiceTest {

@Test

public void add_new_rental() throws Exception {

Car car = new Car(“Ford Fiesta”);

RentalService service = new RentalService();

Date rentalBegin = new SimpleDateFormat(“dd/MM/yy”)

.parse(“22/12/2013”);

Date rentalEnd = new SimpleDateFormat(“dd/MM/yy”)

.parse(“29/12/2013”);

Rental rental =

service.rentACar(“Özcan Acar”, car, rentalBegin,

rentalEnd);

assertTrue(rental.isRented() ) ;

}

Resim 2.3 de yer alan dizge diyagram uygulamanm hangi modüllerden oluştuğuna dair fikir sahibi olmamızı sağlamıştı. Kod 2.1 de yer alan birim testine göz attığımızda, dizge diyagramında yer alan RentalService biriminin Java sınıfı olarak var olduğunu ve sahip olduğu sorumluluk alanına göre kullanıldığını görmekteyiz.

RentalService sınıfının rentACar() metodu ile bir aracm kiralanma işlemi gerçekleştirilmektedir. Bu metot müşteri ismini, kiralanan aracı, kiralama süresinin başlangıç ve bitiş tarihlerini parametre olarak almaktadır. rentACar() metodu bünyesinde yapılan işlemler kod 2.2 de yer almaktadır.

Kod 2.2 – RentalService

package com.kurumsaljava.com.spring;

import java.util.Date;

public class RentalService {

public Rental rentACar(String customerName, Car car,

Date begin, Date end) {

CustomerRepository customerRepository =

Customer customer =

CustomerRepository.getCustomerByName(customerName); if (customer == null) {

customer = new Customer(customerName);

CustomerRepository.save(customer);

}

Rental rental = new Rental();

rental.setCar(car);

rental.setCustomer(customer);

RentalRepository rentRepository = new RentalRepository(); rentRepository.save(rental); return rental;

}

CustomerRepository sınıfı müşteri verilerinden sorumlu olan sınıftır. Veri tabanında yer alan bir müşteri kaydmı bulmak için getCustomerByName() metodunu kullanıyoruz. Eğer getCustomerByName() metodu aradığımız müşteriyi bulamadıysa, new Customer() ile yeni bir müşteri nesnesi oluşturup, save() metodu ile bu müşteriyi veri tabanma ekleyebiliriz.

Bir aracın kiralama işlemi Rental sınıfı ile sembolize edilmektedir. Bu smıf bünyesinde hangi aracm hangi müşteri tarafmdan kiralandığı yer almaktadır. setCar() ve setCustomer() metotları ile kiralanan araç ve aracı kiralayan müşteri oluşturulan rental nesnesine yerleştirilir. Akabinde RentalRepository sınıfının sahip olduğu save() metodu ile rental nesnesi veri tabanma kayıtlanır. Bu metot bünyesinde eğer kayıt esnasmda bir hata oluşmadı ise, rental nesnesinin sahip olduğu rented değişkenine true değeri atanır. Bu durumda isRented() metodu kiralama işleminin olumlu şekilde tamamlandığını gösterecektir.

Bağımlılıkların Enjekte Edilmesi (Dependency Injection)

Kod 2.2 de görüldüğü gibi RentalService smıfı bünyesinde bir kiralama işlemini gerçekleştirebilmek için kullanılan başka sınıflar mevcuttur, örneğin müşteri verilerine ulaşmak için CustomerRepository ve bir rental nesnesini veri tabanma kayıtlamak için RentalRepository sınıfı kullanılmaktadır. Bu iki smıf RentalService sınıfının bağımlılıkları (dependency) olarak adlandırılır. Kısaca RentalService sınıfı bağımlı olduğu sınıflar olmadan iş göremez.

RentalService sınıfını yakından incelediğimizde, rentACar() metodu bünyesinde new operatörü kullanılarak bağımlı olunan sınıflardan nesneler oluşturulduğu görülmektedir. Java’da new operatörü ile yeni nesneler oluşturulur. Lâkin bu şekilde nesne üretmenin beraberinde getirdiği bir dezavantaj vardır. Kod içinde new operatörü kullandığı taktirde, hangi sınıftan bir nesne oluşturulmak istendiği belirtilmek zorundadır. Bu katı kodlama (hard coding) yapmak anlamma gelmektedir, new her zaman derleme esnasında kullanılan smıf tipinin sistem tarafmdan tanınıyor olmasmı gerektirir. Ayrıca başka bir smıf kullanabilmek için kodun değiştirilerek, yeniden derlenmesi gerekmektedir.

Yazılım yaparken karşılaşılan en büyük zorluklardan birisi, bağımlılıkların yönetilmesidir. Kodu değiştirmek zorunda kalmadan, bağımlılıkların yönetimi mümkün olmalıdır. RentalService sınıfında bağımlılıkların katı kodlanması nedeni ile, bağımlılıkların yönetimi çok güçtür. Bağımlılıkların katı kodlanmasına gerek duyulmadan, yönetilebileceği bir mekanizmaya ihtiyaç duyulmaktadır.

new operatörünü kullanmak yerine, RentalService sınıfının ihtiyaç duyduğu nesneleri dışarıdan bu smıfa verebilseydik nasıl olurdu? Metot parametreleri gibi, sınıfın ihtiyaç duyduğu tüm bağımlılıkları dışarıdan enjekte edebiliriz. Bu yönteme bağımlılıkların enjekte edilmesi ismi verilmektedir. RentalService sınıfı için bağımlılıkların nasıl enjekte edildiği kod 2.3 de yer almaktadır.

Kod 2.3 – RentalService package com.kurumsaljava.com.spring; import java.util.Date; public class RentalService {

private CustomerRepository customerRepository;

private RentalRepository rentRepository;

public RentalService(CustomerRepository customerRepository,

RentalRepository rentRepository) { this.customerRepository = customerRepository; this.rentRepository = rentRepository;

}

public Rental rentACar(String customerName, Car car,

Date begin, Date end) {

Customer customer =

customerRepository.getCustomerByName(customerName); if (customer == null) {

customer = new Customer(customerName); customerRepository.save(customer);

}

Rental rental = new Rental(); rental.setCar(car); rental.setCustomer(customer); rentRepository.save(rental) ; return rental;

}

Son yapılan değişiklik ile rentAcar() metodunda kullanılan new operatörleri kaldırmış ve bunun yerine bağımlı olunan sınıflardan oluşan sınıf değişkenleri tanımlamış olduk. Yapılan bu değişiklik ile RentalService sınıfına ihtiyaç duyduğu bağımlılıklar enjekte edilebilir hale gelmiştir. Görüldüğü gibi sınıf konstrüktörü üzerinden CustomerRepository ve RentalRepository sınıflarından oluşturulan nesneler RentalService sınıfına enjekte edilmektedir.

Bu değişikliğin ardından kod 2.1 de yer alan RentalServiceTest sınıfının aşağıdaki şekilde yeniden yapılandırılması gerekmektedir.

Kod 2.4 – RentalServiceTest

package com.kurumsaljava.com.spring;</code>

import static junit.framework.Assert.assertTrue; import j ava.text.SimpleDateFormat;<br/> import java.util.Date;<br/> import org. j unit. Test; <br/x/code>

public class RentalServiceTest {

@Test

public void add_new_rental() throws Exception {

Car car = new Car(“Ford Fiesta”);

CustomerRepository customerRepository = new CustomerRepository() ;

RentalRepository rentalRepository = new RentalRepository();

RentalService service =

new RentalService(customerRepository,

rentalRepository);

Date rentalBegin =

new SimpleDateFormat(“dd/MM/yy”)

.parse(“22/12/2013”);

Date rentalEnd =

new SimpleDateFormat(“dd/MM/yy”)

.parse(“29/12/2013”);

Rental rental =

service.rentACar(“Özcan Acar”, car,

rentalBegin, rentalEnd);

assertTrue(rental.isRented() ) ;

}

Bir sınıfa ihtiyaç duyduğu bağımlılıkların dışarıdan enjekte edilebilmesi için doğal olarak bu bağımlılıkların smıf dışında oluşturulmaları gerekmektedir. Kod

2.4 de görüldüğü gibi RentalService sınıfının ihtiyaç duyduğu iki bağımlılık RentalServiceTest.add«ewrental() metodunda oluşturulmakta ve bu iki bağımlılık RentalService sınıfının konstrüktörü üzerinden bu sınıftan oluşturulan nesneye enjekte edilmektedir.

RentalService sınıfı için gerek duyulan bağımlılıkların dışarıdan enjekte edilebilir hale gelmesi RentalService sınıfını daha esnek hale getirmiştir, örneğin CustomerRepository sınıfını genişleten yeni bir alt smıf oluşturarak, RentalService sınıfına enjekte edebiliriz. Bu yeni smıf örneğin müşteri verilerini veri tabanından değil, başka bir kaynaktan edinmemizi sağlayabilir. RentalService sınıfını değiştirmeden sisteme böylece yeni bir davranış biçimi eklemek mümkündür. Bağımlılıkların enjekte edilmesi metodunun ana amaçlamandan bir tanesi budur.

Spring birçok iş için kullanılabilir, ama en güçlü olduğu saha ve tercih edilme sebeplerinin başmda bağımlılıkların yönetimini ve enjekte edilmesini sağlaması gelmektedir. Bağımlılıkların enjekte edilmesi yöntemi ile kod birimleri arasmda daha esnek bağ oluşturulur. Birbirini kullanan birimler kod değişikliğine gerek kalmadan değişik türde bağımlılıkları kullanabilecek şekilde yeniden yapılandırılabilir. Bu bir nevi değişik kod birimlerini bir araya getirerek, yazılım sistemi konfıgüre etmek gibi bir şeydir.

Spring bağımlılıkların enjekte edilmesi yönteminde interface sınıfların kullanımına ağırlık verir. Eğer bir nesne bağımlı olduğu kod birimlerinin sadece interface sınıflarını tanırsa, Spring bu nesneye ihtiyaç duyduğu interface sınıfların herhangi bir implementasyonunu enjekte edebilir. RentalService sınıfının Spring kullanılarak nasıl yeniden yapılandırılabileceğini bir sonraki bölümde yakından inceleyelim.

Spring İle Bağımlılıkların Enjekte Edilmesi

Bu bölümde araç kiralama servisi uygulamasmı Spring kullanarak yeniden yapılandıracağız. Spring bağımlılıkların tanımlanması için bir XML dosyası kullanır. Bu konfigürasyon dosyası Spring sunucusunu oluşturmak için gerekli tüm meta bilgileri ihtiva eder. Spring sunucusu kavramını bir sonraki bölümde inceleyeceğiz. Şimdilik bunu çalışır durumda olan bir Spring uygulaması olarak düşünebilirsiniz.

Spring 3.0 ile XML dosya kullanma zorunluluğu kalkmıştır. ©Configuration anotasyonu kullanılarak Java bazlı Spring konfigürasyonu yapılabilir. Yinede Spring’in temellerini daha iyi anlayabilmek için bu bölümde XML bazlı konfigürasyonu inceleyeceğiz.

Bağımlılıkların Spring tarafmdan yönetilebilmesi için mevcut kod birimlerinin Spring XML dosyasmda tanımlanması gerekmektedir. Spring XML dosyasmda tanımlanan her kod birimine Spring bean (Spring nesnesi) ismi verilmektedir. Bundan sonraki bölümlerde Spring bean yanı sıra Spring nesnesi tanımlaması ya da bean tanımlaması terimlerini kullanacağım.

Araç kiralama servisi uygulamasında Spring XML dosyasmda tanımlamamız gereken Spring nesneleri RentalServicelmpl, CustomerRepositorylmpl ve RentalRepositorylmpl sınıflarıdır.

Kod 2.5 – applicationContext.xml <?xml version=”l.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/

spring-beans-3.0.xsd”>

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServicelmpl”>

<constructor-arg ref=”customerRepository” />

<constructor-arg ref=”rentalRepository” />

</bean>

<bean id=”customerRepository”

class=”com.kurumsaljava.spring.CustomerRepositorylmpl” />

<bean id=”rentalRepository”

class=”com.kurumsaljava.spring.RentalRepositorylmpl” />

</beans>

Herhangi bir Java sınıfı <bean/> XML elementi kullanılarak Spring nesnesi olarak tanımlanabilir. Kod 2.5 de yer alan Spring XML dosyasmda rentalService, customerRepository ve rentalRepository isimlerinde üç Spring nesne tanımlaması yer almaktadır.

<bean/> bünyesinde kullanılabilecek element özellikleri (attribute) aşağıda yer almaktadır. Bu element özelliklerinin nasıl kullanıldığını kitabın bu ve diğer bölümlerinde inceleyeceğiz.

• class – Kullanılan sınıfı tanımlar.

• id – Oluşturulan Spring nesnesinin tekil tanımlayıcısıdır.

• name – Bir Spring nesnesine id haricinde birden fazla isim vermek için kullanılır, isimler arasında virgül kullanılarak birden fazla isim tanımlanabilir, id ve name element özelliklerine sahip olmayan Spring nesne tanımlamaları anonimdir ve doğrudan başka nesnelere enjekte edilemezler.

• abstract – Nesne tanımlamasını soyutlaştırır. Bu tür Spring nesne tanımlamalarından nesneler oluşturulmaz. Soyut Spring nesne tanımlamaları başka Spring nesnelerin üst tanımlaması olarak kullanılır.

• parent – Kullanılacak üst soyut Spring nesne tanımlamasını belirlemek için kullanılır.

• scope – Varsayılan scope singleton yani tekil scopodur. Bu Spring sunucusundan bir nesne talep ettiğimizde singleton olan aynı nesneyi edindiğimiz anlamma gelmektedir, prototype scope kullanıldığında Spring her isteğe yeni bir nesne ile cevap verir.

• constructor-arg – Smıf konstrüktörü aracılığı ile bağımlılıklar enjekte edilmek istendiğinde kullanılır.

• property – Enjeksiyon yapılacak sınıf değişkenini tanımlar.

• init-method – Nesneler enjekte edildikten sonra koşturulacak sınıf metodunu tanımlar. Bu metodun parametresiz olması gerekmektedir.

• destroy-method – Spring sunucusu son bulduğunda sunucu bünyesinde bulunan nesneleri sonlandırmak için kullanılan metotları tanımlar. Bu metodun parametresiz olması gerekmektedir. Sadece Spring sunucusu tarafından kontrol edilen nesneler üzerinde tanımlanabilir.

• factory-bean – Bu nesneyi oluşturabilecek fabrika sınıfını (Factory Bean) tanımlar, factory-bean kullanıldığı taktirde sınıf değişkenleri üzerinden enjeksiyon yapılmamalıdır.

• factory-method – Bu nesneyi oluşturmak için kullanılacak fabrika metodunu tanımlar.

Kod 2.3 de yer alan RentalService sınıfına tekrar göz attığımızda, bu sınıfın ve bağımlılık duyduğu diğer sınıfların somut sınıflar olduğunu görmekteyiz. Genel olarak bağımlılıkların soyut sınıflar yönünde olmasında fayda vardır, çünkü sadece bu durumda smıfa istediğimiz bir implementasyon nesnesini enjekte edebiliriz. Bunun yanı sıra Spring bean olarak tanımladığımız sınıfın da bir interface sınıf implementasyonu olması faydalıdır. Bu şekilde Spring birden fazla implementasyonu yönetebilir. Nitekim kod 2.5 de Spring bean tanımlamalarında kullandığımız sınıflar şu interface sınıfları implemente etmektedirler:

public interface RentalService{

public Rental rentACar(String customerName,

Car car, Date begin, Date end);

}

public interface RentalRepository{ public void save(Rental rental); }

public interface CustomerRepository{

public Customer getCustomerByName(String name); public void save(Customer customer);

}

Spring bir nesneye ihtiyaç duyduğu bağımlılıkları sahip olduğu sınıf değişkenleri, set metotları ya da sınıf konstrüktörleri üzerinden enjekte edebilir. Kod 2.5 de yer alan örnekte rentalService ismini taşıyan Spring nesnesi bağımlılıkları constructor-arg kullanılarak sınıf konstrüktörleri üzerinden enjekte edilmektedir. RentalServicelmpl sınıfının sahip olduğu smıf değişkenleri ve bu değişkenlerin smıf kontrüktörü üzerinden nasıl enjekte edildiği kod 2.6 da yer almaktadır.

Kod 2.6 – RentalServicelmpl

package com.kurumsaljava.spring;<br/> import java.util.Date;

public class RentalServicelmpl implements RentalService {

private CustomerRepository CustomerRepository; private RentalRepository rentalRepository;

public RentalServicelmpl(CustomerRepository CustomerRepository, RentalRepository rentalRepository) { super();

this.CustomerRepository = CustomerRepository; this.rentalRepository = rentalRepository;

}

@Override

public Rental rentACar(String customerName, Car car, Date

begin, Date end) {

Customer customer =

CustomerRepository.getCustomerByName(customerName); if (customer == null) {

customer = new Customer(customerName);

CustomerRepository.save(customer);

}

Rental rental = new Rental(); rental.setCar(car); rental.setCustomer(customer); rentalRepository.save(rental); return rental;

}

Spring’in bir bağımlılığı enjekte edebilmesi için hangi Spring nesnesini nereye enjekte edeceğini bilmesi gerekir. Nereye sorusuna constructor-arg ile cevap verdik. Hangi sorusuna ise constructor-arg elementinde kullanılan ref ile cevap verebiliriz, ref referans anlamına gelmektedir ve enjekte edilecek bağımlılığa işaret eder. rentalService örneğinde CustomerRepository ve rentalRepository isimlerini taşıyan iki Spring nesnesi sınıf konstrüktörü üzerinden rentalService nesnesine enjekte edilmektedir. Spring’in bu iki nesneyi rentalService nesnesine enjekte edebilmesi için CustomerRepository ve rentalRepository isimlerini taşıyan Spring nesnelerin XML dosyasında tanımlanmış olması gerekmektedir. Spring tanımlanan Spring nesne isimlerini kullanarak gerekli olan bağımlılıkları enjekte eder.

RentalServicelmpl sınıfının konstrüktöründe kullanılan parametrelerin belli bir sırası vardır. İlk parametre CustomerRepository sınıfından bir nesne, ikinci parametre RentalRepository sınıfından bir nesnedir. RentalServicelmpl sınıfından sahip olduğu bu iki parametreli sınıf konstrüktörü üzerinden bir nesne oluştururken, parametrelerin hangi sıra ile konstrüktöre verildiği önemlidir. Spring XML dosyasmda bu parametre sırası nasıl belirtilir? Kod 2.5 de yer alan XML dosyasmda rentalService için böyle bir sıra tanımlaması yapmadık. Spring ilk etapta böyle bir sıralamaya ihtiyaç duymamaktadır. Spring tanımlanan Spring nesnelerin hangi Java sınıfından oluşturulduğunu (class aracılığı ile) bildiği için bağımlılıkları kontrüktöre enjekte ederken doğru nesneyi doğru sırada enjekte eder. Bir konstrüktör aynı Java sınıfından olan birden fazla parametre almadığı sürece bir sorun oluşmaz. Eğer smıf konstrüktörü aynı Java sınıfından olan birden fazla parametreye sahip ise, Spring’in bağımlılıkları enjekte ederken kafası karışabilir. Bunu engellemek için aşağıdaki şekilde parametre sırası belirtilebilir.

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServicelmpl”> <constructor-arg ref=”customerRepository” index=”0″/>

<constructor-arg ref=”rentalRepository” index=”l”/>

</bean>

Spring 3.0 dan itibaren konstrüktör parametresinin ismini kullanarak enjeksiyon yapmak mümkündür. Spring’in Java byte kodunda parametre isimlerini bulabilmesi için byte kodun debug flag kullanılarak derlenmiş olması gerekmektedir. Aksi taktirde değişken isimleri byte kod içinde olmayacağmdan, bu yöntem kullanılarak bağımlılıklar enjekte edilemez.

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServicelmpl”>

<constructor-arg name=”customerRepository”

ref=”customerRepository”/>

<constructor-arg name=”rentalRepository”

ref=”rentalRepository”/>

</bean>

JDK bünyesinde yer alan @ConstructorProperties anotasyonu ile konstrüktör parametrelerini kod içinde şu şekilde işaretleyebiliriz:

SConstructorProperties({“rentalRepository”, “custromerRepository”}) public RentalService(RentalRepository rentalRepository,

CustomerRepository customerRepository ) {

this.rentalRepository = rentalRepository; this.customerRepository = customerRepository;

}

Spring ile oluşturduğumuz bu yeni yapıyı nasıl kullanabiliriz? Bunun cevabı kod

2.7 de yer almaktadır.

Kod 2.7 – Main

package com.kurumsaljava.spring; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;

import org.springframework.context.ApplicationContext; import org.springframework.context.support.

ClassPathXmlApplicationContext;

public class Main {

public static void main(String[] args) throws Exception {

ApplicationContext ctx =

new ClassPathXmlApplicationContext(”

applicationContext.xml”);

RentalService rentalService =

(RentalService) ctx.getBean(“rentalService”);

Rental rental = rentalService.

rentACar(“Özcan Acar”, new Car(“Fiesta”), getRentalBegin(), getRentalEnd());

System.out.println(“Rental status: ”

+ rental.isRented());

}

private static Date getRentalEnd() throws ParseException { return new SimpleDateFormat(“dd/MM/yy”).

parse(“29/12/2013”);

}

private static Date getRentalBegin()

throws ParseException { return new SimpleDateFormat(“dd/MM/yy”).

parse(“22/12/2013”);

}

Idref Kullanımı

Idref ile konfigürasyon dosyasında tanımlı olan herhangi bir Spring nesnesinin ismini herhangi bir sınıf değişkenine enjekte edebiliriz.

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServiceImpl”>

<property name=”targetName”>

<idref bean=”customerRepository” />

</property>

</bean>

Bu örnekte targetName isimli değişkene bir Spring nesnesinin ismi olan customerRepository enjekte edilmemektedir. Burada targetName isimli değişkene atanan bir String değerdir. Bu değer customerRepository String nesnesidir. Bu tanimlamayı şu şekilde de yapabilirdik:

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServiceImpl”>

<property name=”targetName” value=”customerRepository”/>

</bean>

idref kullanıldığı taktirde Spring uygulama çalışmaya başlamadan önce customerRepository ismini taşıyan bir Spring nesnesi tanımlaması olup, olmadığı kontrol eder. Eğer böyle bir tanımlama yoksa, Spring uygulamayı durdurur ve hata bildiriminde bulunur. Verdiğim ikinci örnekte targetName değişkenine doğrudan customerRepository değeri atandığında, Spring bu değeri kontrol etmez. Eğer yanlış bir değer kullanıldıysa, bu hata uygulama çalışırken gün ışığına çıkacaktır. Bu sebepten dolayı mevcut Spring nesne isimleri idref kullanılarak değişkenlere enjekte edilmelidir, çünkü sadece bu şekilde bu isimlerin hatalı olup, olmadıkları hemen anlaşılabilir.

idref elementinin local element özelliği kullanıldığı taktirde, Spring bu ismi taşıyan Spring nesnesinin idref’in kullanıldığı konfigürasyon dosyasında tanımlanıp, tanımlanmadığını kontrol eder. Spring böyle bir nesne tanımlaması bulamaması durumunda uygulamayı durdurur ve hata bildiriminde bulunur.

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServiceImpl”>

<property name=”targetName”>

<idref local=”customerRepository” /> </property>

</bean>

Spring Sunucusu ve BeanFactory

Spring uygulamasının çalışabilir hale gelmesi için Spring konfigürasyonunun yer aldığı XML dosyasmın hafızaya yüklenmesi gerekmektedir. Bu amaçla org.springframework.context.ApplicationContext sınıfı ve türevleri kullanılır. ApplicationContext org.springframework.beans.factory.BeanFactory interface smıfını genişletir. Spring sunucusunu temsil eden en üst sınıf BeanFactory sınıfıdır. Bu sınıf Spring sunucusunda yer alan nesnelerin konfigürasyonunu ve bu nesnelere erişimi tanımlar. BeanFactory Spring’in temel konfigürasyon yapısıdır.

ApplicationContext türevlerinden bir tanesi ClassPathXmlApplicationContext sınıfıdır. ClassPathXmlApplicationConect ile Java classpath içinde bulunan bir XML dosyası yüklenerek, Spring uygulaması çalışır hale getirilir.

Application Context Resim2.5

Kod 2.7.1 de yer alan satır Spring sunucusunu oluşturur. Sunucuyu oluşturmak için gerekli tüm meta bilgiler applicationContext.xml ismini taşıyan XML dosyasında yer almaktadır.

Kod 2.7.1 – Main

ApplicationContext ctx =

new ClassPathXmlApplicationContext(”

applicationContext.xml”);

ClassPathXmlApplicationContext sınıfı kullanılarak Spring XML dosyasının yüklenmesi hafızada Application Context ismi verilen bir yapıyı oluşturur. Bunu Spring uygulamasının hafızadaki yüklenmiş hali olarak düşünebiliriz. ApplicationContext bu yapıyı temsil eden interface sınıftır. Bu yapıya Spring Container, yani Spring sunucusu ismi verilmektedir. Spring, XML dosyasmda tanımlanmış tüm Spring nesneleri tarayarak, önce hiç bağımlılığı olmayan Spring nesne tanımlamalarından nesneler oluşturur. Daha sonra bu nesneleri bağımlılık duyan diğer nesnelere enjekte eder. Bu işlem sonunda her Spring nesne tanımlaması için bir nesne oluşturularak, hafızada yer alan Application Context bünyesinde konuşlandırılmış olur.

Hafızada yer alan Application Context bünyesindeki rentalService isimli Spring nesnesine erişmek için ctx.getBean( “rentalService”) şeklinde bir çağrı yapmamız yeterli olacaktır. getBean() metodu bize istediğimiz Spring nesnesini sanki new yapmışcasına geri verir. Artık new operatörünü kullanan biz değil, Spring’dir. Spring Java’nın Reflection özelliğinden faydalanarak nesneleri oluşturur.

Spring 3 ile oluşturulan yeni getBean() metodu ile cast yapmak zorunda kalmadan şu şekilde bir rentalService nesnesi edinebiliriz:

RentalService rentalService =

ctx.getBean(“rentalService”, RentalService.class);

Eğer kullandığımız interface sınıfın sadece bir implementasyon sınıfını Spring nesnesi olarak tanımladıysak, aşağıdaki şekilde Spring nesnesinin ismini kullanmadan bir rentalService nesnesi edinebiliriz:

RentalService rentalService =

ctx.getBean(RentalService.class);

Kod 2.5 de yer alan XML konfigürasyon dosyasma tekrar göz attığımızda rentalService isimli Spring nesneyi tanımlamak için RentalServicelmpl sınıfını

RentalService rentalService = (RentalService) ctx.getBean(“rentalService”);

şeklinde bir tanımlama ile rentalService nesnesini kullanıyoruz? RentalService tanımladığımız interface sınıftır.

Resim2.6 Resim 2.6

public interface RentalService {

public Rental rentACar(String customerName, Car car,

}

Date begin, Date end);

RentalService soyut bir interface sınıfıdır. Kod içinde RentalService interface sınıfını kullanarak somut sınıflara olan bağımlılığımızı ortadan kaldırmış oluyoruz. RentalService interface sınıfını implemente eden yeni bir sınıf oluşturarak, kod 2.7 de yer alan Main sınıfını değiştirmek zorundan kalmadan, bu oluşturduğumuz yeni implementasyon sınıfını kullanabiliriz. Bunun için yapmamız gereken tek şey, Spring XML dosyasında rentalService ismini taşıyan Spring nesnesinin kullandığı sınıfı değiştirmek olacaktır.

Tekrar kod 2.2 ye göz attığımızda, Spring’in bizim için üstlendiği görevi net olarak görmek mümkündür. Spring öncesi her bağımlılığı new ile kendimiz oluştururken, Spring ile bunu yapma zorunluluğu ortadan kalkmıştır. Ayrıca oluşturduğumuz yeni uygulamanm bağımlılıkların tersine çevrilmesi tasarım prensibine DIP – Dependency Inversion Principle uygun hale geldiğini görmekteyiz. Bu tasarım prensibi uygulamanm meydana gelebilecek değişikliklere karşı daha dayanıklı hale gelmesini sağlamaktadır. Spring ayrıca

interface sınıfları kullanmayı teşvik ederek, uygulamayı değiştirmeden uygulamaya yeni davranış biçimleri eklemeyi mümkün kılmaktadır. Daha fazlası can sağlığı demeyin. Spring’in uygulama geliştirirken bizim için üstlenebileceği daha birçok şey var. İlerleyen bölümlerde Spring’in bizim için yapabileceklerini daha yakından inceleyeceğiz. Kısaca Spring’in var olma nedenini tanımlamak istersek, “Spring yazılımcının hayatini kolaylaştırmak için vardır” dememiz yanlış olmaz.

Spring Nesne İsimlendirme

Application Context bünyesinde yer alan her Spring nesnesinin bir ya da birden fazla ismi vardır. Spring sunucusu bünyesinde bu isimlerin tekil olması gerekmektedir. Aynı ismi iki değişik Spring nesnesi paylaşamaz.

Şimdiye kadar kullandığımız örneklerde id element özelliği aracılığı ile oluşturduğumuz Spring nesne tanımlamalarına isimler verdik. Tanımladığımız bu isimler aracılığı ile Spring nesnelerine erişmemiz mümkün oldu.

id element özelliği bünyesinde sadece bir isim barındırabilir, yani her nesne tanımlamasına id element özelliği ile sadece bir isim atanabilir. Bunun yanı sıra Spring 3.1 öncesi id element özelliği bünyesinde / ve : gibi işaretler kullanmak mümkün değildi. Spring 3.1 ile aşağıdaki şekilde bir nesne tanımlaması mümkün olmuştur.

<bean id=”clio/myclio” …/>

Car clio = ctx.getBean(“clio/myclio”, Car.class);

Bu değişiklik ne yazık ki bir Spring nesne tanımlamasına birden fazla ismi atayamama sorununu çözmemektedir. Bu sorunu çözmek için name element özelliği kullanılabilir, örneğin yukarıda tanımlamış olduğumuz clio nesnesine aynı zamanda myclio ya da yourclio isimlerini atamak isteseydik, o zaman şu şekilde bir bean tanımlaması yapardık:

<bean id=”clio” name=”myclio, yourclio” …/>

Bir Spring nesnesi tanımlarken id ya da name element özelliklerini kullanma zorunluluğu bulunmamaktadır. Bu element özellikleri ile Spring nesnesine bir isim atanmadığı taktirde, Spring sunucusu bu nesneye otomatik olarak bir isim atar. İsmi olmayan Spring nesneleri anonimdir ve isimleri olmadığı için ref element özelliği kullanılarak diğer nesnelere enjekte edilemezler.

Mevcut Spring nesnelerine yeni isimler atamak için kullanılabilecek diğer bir element <alias/> elementidir, örneğin

<alias name=”birlsim” alias=”baskaBirIsim”/>

ile birisim ismini taşıyan Spring nesnesine baskaBirlsim ismini kullanarak ta erişmek mümkün olmaktadır.

Bağımlılıkları Enjekte Etme Türleri

RentalServicelmpl sınıfının ihtiyaç duyduğu bağımlılıkları sınıf konstrüktörü üzerinden constructor-arg elementi ile enjekte etmiştik. Bu bağımlılıkları enjekte etmek için kullanabileceğimiz yöntemlerden bir tanesidir. Bunun yanı sıra bağımlılıklar property elementi ile de enjekte edilebilir.

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServicelmpl”>

<property name=”customerRepository” ref=”customerRepository” /> <property name=”rentalRepository” ref=”rentalRepository” />

</bean>

property elementi sınıf bünyesindeki bir sınıf değişkenine işaret etmektedir. Hangi sınıf değişkenine bağımlılığın enjekte edilmesi gerektiğini name element özelliği ile tanımlıyoruz. Kllandığımız örnekte (bakınız kod 2.6) sınıf değişkeninin ismi customerRepository ya da rentalRepository’dir. Eğer sınıf değişkenleri bu isim ile tanımlanmadı ise, Spring istenilen bağımlılıkları enjekte edemez. Hangi bağımlılığın sınıf değişkenine enjekte edilmesi gerektiğini ref element özelliği ile tanımlıyoruz. Kod 2.5 e tekrar göz attığımızda customerRepository ve rentalRepository ismini taşıyan iki Spring nesnesi tanımlamasının mevcut olduğunu görmekteyiz. Bu örnekte sınıf değişkenleri ve Spring nesneleri aynı ismi taşımaktadır.

Bağımlılıkların property elementi kullanılarak enjekte edilebilmesi için sınıf değişkenlerinin set() metotlarına sahip olması gerekmektedir. Bunun yanı sıra sınıf parametresiz bir sınıf konstrüktörüne ihtiyaç duymaktadır.

ı

Kod 2.8 – RentalServicelmpl

package com.kurumsaljava.spring; import java.util.Date;

public class RentalServicelmpl implements RentalService {

private CustomerRepository customerRepository; private RentalRepository rentalRepository;

public RentalServicelmpl() {

}

public RentalServicelmpl(

CustomerRepository customerRepository,

RentalRepository rentalRepository) { super();

this.customerRepository = customerRepository; this.rentalRepository = rentalRepository;

}

@Override

public Rental rentACar(String customerName, Car car,

Date begin, Date end) {

Customer customer =

customerRepository.getCustomerByName(customerName); if (customer == null) {

customer = new Customer(customerName); customerRepository.save(customer);

}

Rental rental = new Rental(); rental.setCar(car); rental.setCustomer(customer); rentalRepository.save(rental); return rental;

}

public CustomerRepository getCustomerRepository() { return customerRepository;

}

public void setCustomerRepository(CustomerRepository

customerRepository) { this.customerRepository = customerRepository;

}

public RentalRepository getRentalRepository() { return rentalRepository;

}

public void setRentalRepository(RentalRepository

rentalRepository) { this.rentalRepository = rentalRepository;

}

Eğer bağımlılıkların enjekte edilmesi için property elementini kullandıysak, Spring bağımlılıkların enjekte edileceği sınıftan parametresiz sınıf konstrüktörünü kullanarak yeni bir nesne oluşturur. Akabinde Spring setCustomerRepository() ve setRentalRepository() metotlarını kullanarak tanımlanmış olan bağımlılıkları enjekte eder. Spring’in bir RentalServicelmpl nesnesini nasıl oluşturduğunu anlamak için bir sonraki kod bloğuna göz atalım.

RentalServicelmpl service = new RentalServicelmpl();

CustomerRepositoryImpl customerRepository =

new CustomerRepositoryImpl();

RentalRepositoryImpl rentalRepository =

new RentalRepositorylmpl(); service.setCustomerRepository(customerRepository); service.setRentalRepository(rentalRepository);

Eğer kendimiz bir RentalServicelmpl nesnesi oluşturmak isteseydik, bir önceki kod bloğundaki gibi işlem yapmamız gerekirdi. Oysaki Spring aracılığı ile bir RentalServicelmpl nesnesi edinmek için yapmamız gereken tek işlem

RentalService rentalService =

(RentalService) ctx.getBean(“rentalService”);

şeklindedir.

Bağımlılıkların enjekte edilmesi için hangi yöntemi kullanmalıyım sorusu aklınıza gelmiş olabilir. Seçiminizi sadece bir yönde yapmak zorunda değilsiniz. Her iki yöntemi de birlikte kullanabilirsiniz. Bir sonraki kod bloğunda hem constructor-arg hem de property elementleri beraber kullanılmaktadır.

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServiceImpl”>

<constructor-arg ref=”customerRepository”/>

<property name=”rentalRepository” ref=”rentalRepository” /> </bean>

Spring her iki enjekte metodu birlikte kullanıldığında, bir sonraki kod bloğundaki işlemleri gerçekleştirir.

CustomerRepositoryImpl customerRepository =

new CustomerRepositoryImpl();

RentalServicelmpl service =

new RentalServicelmpl(customerRepository); RentalRepositorylmpl rentalRepository =

new RentalRepositorylmpl(); service.setRentalRepository(rentalRepository);

Eğer sonradan değiştirilemeyen, sabit (immutable) nesneler oluşturmak istiyorsanız, seçiminiz constructor-arg yönünde olmalıdır. Bir sınıftan sabit bir nesne oluşturmak için set metotlarının kaldırılması ve sadece bağımlıkları parametre olarak alan bir smıf konstrüktörü kullanılması gerekir, örneğin RentalServicelmpl sınıfından sabit bir nesne oluşturmak için kod 2.9 da yer alan implementasyon kullanılabilir.

Kod 2.9 – RentalServicelmpl

package com.kurumsaljava.spring; import java.util.Date;

public class RentalServicelmpl implements RentalService {

private final CustomerRepository customerRepository; private final RentalRepository rentalRepository;

public RentalServicelmpl(

CustomerRepository customerRepository,

RentalRepository rentalRepository) { super();

this.customerRepository = customerRepository; this.rentalRepository = rentalRepository;

}

@Override

public Rental rentACar(String customerName, Car car,

Date begin, Date end) {

Customer customer =

customerRepository.getCustomerByName(customerName); if (customer == null) {

customer = new Customer(customerName); customerRepository.save(customer);

}

Rental rental = new Rental(); rental.setCar(car); rental.setCustomer(customer); rentalRepository.save(rental); return rental;

}

Listelerin Enjekte Edilmesi

Spring nesneler yanı sıra konfigürasyonu tanımlanan listeleri de enjekte edebilir, örneğin RentalServicelmpl sınıfına kiralanabilecek araç listesini enjekte etmek isteseydik, bir sonraki kod bloğundaki gibi araç listesini oluştururduk.

bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServicelmpl”>

<constructor-arg ref=”customerRepository” />

<constructor-arg ref=”rentalRepository” />

<property name=”carList”>

<list>

<ref bean=”fiesta” />

<ref bean=”clio” />

</list>

</property>

</bean>

<bean id=”fiesta” class=”com.kurumsaljava.spring.Car”>

<constructor-arg name=”brand” value=”ford” />

<constructor-arg name=”model” value=”fiesta” />

</bean>

<bean id=”clio” class=”com.kurumsaljava.spring.Car”>

<constructor-arg name=”brand” value=”renault” />

<constructor-arg name=”model” value=”clio” />

</bean>

Araç listesinin RentalServicelmpl sınıfından oluşturulan bir nesneye enjekte edilebilmesi için RentalService bünyesinde bir sonraki kod bloğunda görüldüğü gibi List veri tipinde bir listenin tanımlanması gerekmektedir.

private List<Car> carList;

public List<Car> getCarListO { return carList;

public void setCarList(List<Car> carList) { this.carList = carList;

Main sınıfını Eclipse Debugger ile koşturduğumuzda, Spring’in XML dosyasında tanımlandığı şekilde iki Car nesnesini oluşturarak, RentalServicelmpl sınıfında yer alan carList listesini eklediğini görmekteyiz.

Resim2.7 Resim 2.7

Arka planda Spring’in araç listeni oluşturmak için yaptığı işlemler bir sonraki kod bloğunda yer almaktadır.

CustomerRepositoryImpl CustomerRepository =

new CustomerRepositoryImpl();

RentalRepositoryImpl rentalRepository =

new RentalRepositoryImpl() ;

RentalServicelmpl service =

new RentalServicelmpl(CustomerRepository,

rentalRepository) ;

Car fiesta = new Car(“ford”, “fiesta”);

Car clio = new Car(“renault”, “clio”);

List<Car> carList = new ArrayList<Car>();

carList.add(fiesta) ; carList.add(clio) ; service.setCarList(carList) ;

Map tipi bir koleksiyon aşağıdaki şekilde enjekte edilebilir.

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServiceImpl”> <property name=”carMap”>

<map>

<entry key=”fiesta”>

<ref bean=”fiesta” />

</entry>

<entry key=”clio”>

<ref bean=”clio” />

</entry>

</map>

</property>

</bean>

Set tipi bir koleksiyon aşağıdaki şekilde enjekte edilebilir.

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServiceImpl”> <property name=”carSet”>

<set>

<ref bean=”fiesta” />

<ref bean=”clio” />

</set>

</property>

</bean>

java.util.Properties tarzı bir özellik listesi aşağıdaki şekilde enjekte edilebilir.

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServiceImpl”> <property name=”carProperty”>

<props>

<prop key=”ford”> fiesta </prop>

<prop key=”renault”> clio </prop>

</props>

</property>

</bean>

Basit Değerlerin Enjekte Edilmesi

Enjekte edilmek istenen değerler int ya da String gibi basit değerler olabilir, property elementi kullanılarak bu tür enjeksiyonları gerçekleştirmek mümkündür, örneğin CustomerRepositorylmpl sınıfında database ismini taşıyan bir String değişken olsaydı, bu değişkene aşağıdaki şekilde bir değer enjeksiyonu yapabilirdik.

<bean id=”customerRepository”

class=”com.kurumsaljava.spring.CustomerRepositoryImpl”>

<property name=”database” value=”oracle” />

</bean>

Yukarıda yer alan örnekte CustomerRepositorylmpl sınıfının database isimli smıf değişkenine oracle değeri enjekte edilmektedir. Bunun sağlanabilmesi için CustomerRepository isimli sınıfın database isimli bir değişkene ve bu değişkene değer atanmasında kullanılacak setDatabase() metoduna sahip olması gerekmektedir. Spring’in customerRepository isimli bir nesneyi oluşturmak için yaptığı işlem aşağıda yer almaktadır.

CustomerRepositorylmpl customerRepository =

new CustomerRepositorylmpl(); customerRepository.setDatabase(“oracle”);

value elementini kullanarak ta deüişkenlere değerler enjekte edilebilir:

<property name=”database”><value>oracle</valueX/property>

ya da

<constructor-arg type=int><value>l0 0 0 0</value></constructor-arg>

Null ya da Boş String Değerinin Enjekte Edilmesi

property elementinin value element özelliği boş bırakıldığı taktirde, bu değişkene sıfır uzunluğunda bir String nesnesinin enjekte edildiği anlamana gelmektedir.

<bean id=”customerRepository”

class=”com.kurumsaljava.spring.CustomerRepositoryImpl”>

<property name=”database” value=”” />

</bean>

Eger bir değişkene null değerini atamak istiyorsak, <null/> elementini kullanabiliriz.

<bean id=”customerRepository”

class=”com.kurumsaljava.spring.CustomerRepositoryImpl”> <property name=”database”Xnull/x/property>

</bean>

Nesne Oluşturma Sırasının Tanımlanması

Normal şartlar altında iki nesne arasındaki bağımlılık ref elementi kullanıldığı taktirde, nesnelerin oluşturulma sırası tanımlanmış olur. Spring bu durumda ilk önce enjekte edilecek nesneyi oluşturur, daha sonra bu nesnenin enjekte edileceği diğer nesneyi. Bunun yanı sıra depends-on elementi ile de nesne oluşturma sırası tayin edilebilir. Aşağıda yer alan örnekte Spring customerRepository nesneyi oluşturmadan önce, dbManager isimli nesneyi oluşturur. Bu genel olarak bir nesnenin sebep olduğu yan etkilere bağımlı olunduğu durumlar kullanılan bir yöntemdir.

<bean id=”customerRepository”

class=”com.kurumsaljava.spring.CustomerRepositoryImpl” depends-on=”dbManager”/>

<bean id=”dbManager”

class=”com.kurumsaljava.spring.DbManager” />

depends-on bünyesinde birden fazla bean ismi tanımlaması şu şekilde yapılabilir:

<bean id=”customerRepository”

class=”com.kurumsaljava.spring.CustomerRepositoryImpl” depends-on=”dbManager, txManager, myBean”/>

Uygulama son bulduğunda da tanımlanan bu sıranın tam tersine göre nesneler imha edilir.

Otomatik Veri Tipi Dönüşümü

Basit değerlerin enjeksiyonu için property elementinin value özelliği ile nasıl beraber kullanıldığını bir önceki bölümde gördük, value özelliği içinde tanımlanan değer yapı itibari ile bir String nesnesidir. Eğer bir int veri tipine sahip bir değişkene değer enjekte etmek istersek, value özelliğinde yer alan bu değer Spring tarafından otomatik olarak bir int değerine dönüştürülür. Aşağıda yer alan kod örneğinde int veri tipinde olan port değişkenine 1234 değeri enjekte edilmektedir. Bu değer otomatik olarak Spring tarafından 1234 rakamına dönüştürülerek, port isimli int değişkenine enjekte edilmektedir.

<bean id=”customerRepository”

class=”com.kurumsaljava.spring.CustomerRepositoryImpl”>

<property name=”port” value=”1234″ />

</bean>

float, double gibi diğer basit verit tipleri için de Spring tarafından otomatik veri tipi dönüşümü sağlanır.

Tekil Nesneler ve Bean Scope

Çoğu yazılımcı tarafından tasarım şablonu olarak görülmese de tekillik singleton tasarım şablonu ismini taşıyan bir tasarım şablonu mevcuttur. Tekillik tasarım şablonu ile bir sınıftan sadece bir nesne oluşturulması amaçlanır.

Spring için varsayılan nesne oluşturma ayarı tekil nesnedir. Bunun ispatı için bir sonraki kod bloğunu inceleyelim.

System.out.println((RentalService) ctx.getBean(“rentalService”)); System.out.println((RentalService) ctx.getBean(“rentalService”));

Ekra çıktısı:

com.kurumsaljava.spring.RentalServiceImpl@18c908b com.kurumsaljava.spring.RentalServiceImpl@18c908b

getBean() metodu ile rentalService nesnesini edindiğimizde, sahip oldukları adres alanlarının (@18c908b) aynı olduğunu görmekteyiz. Bu Spring’in rentalService ismini taşıyan nesneyi hafızada sadece bir kez tuttuğunun kanıtıdır. Eğer getBean() metodu üzerinden her defasında yeni bir rentalService nesnesi edinmek istiyorsak, rentalService’in bean tanımlamasını bir sonraki kodda yer aldığı şekilde değiştirmemiz gerekmektedir.

CustomerRepositorylmpl customerRepository =

new CustomerRepositorylmpl();

customerRepository.setDatabase(“oracle”);

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServicelmpl” scope=”prototype”>

<constructor-arg ref=”customerRepository” />

<constructor-arg ref=”rentalRepository” />

</bean>

Tekil nesne oluşturmayı önleyen scope=”prototype” tanımlamasıdır, scope ile nesnenin ömrü tanımlanır, scope bünyesinde kullanılabilecek değerler şunlardır:

• singleton: Tekil nesne tanımlamak için kullanılır. Spring tarafmdan varsayılan scope singletondır.

• prototype: Spring sunucusundan her talep için yeni bir nesne oluşturulur.

• request: Web uygulamalarmda bir istek (http request) boyunca geçerli olan nesne oluşturulmak için kullanılır. Sadece web uyumlu bir Application Context (örneğin Spring MVC uygulaması) oluşturulduğunda kullanılabilir.

• session: Web uygulamalarmda kullanıcı oturumu (http session) boyunca geçerli olan nesne oluşturmak için kullanılır. Sadece web uyumlu bir Application Context (örneğin Spring MVC uygulaması) oluşturulduğunda kullanılabilir.

• globalSession: Portlet uygulamalarmda tüm uygulama parçaları için geçerli olan kullanıcı oturumunda (global http session) kullanılmak üzere nesne oluşturmak için kullanılır. Sadece web uyumlu bir Application Context (örneğin Spring MVC uygulaması) oluşturulduğunda kullanılabilir.

• custom: Yazılımcı tarafmdan oluşturulur Spring sunucusu yazılımcının tayin ettiği şekilde nesne oluşturma sürecini yönlendirir.

Scope Bazlı Nesnelerin Enjeksiyonu

Scope bazlı nesnelerin bazı şartlar altmda singleton ya da prototype olan nesnelere enjeksiyonu sorun oluşturabilir. Aşağıda yer alan örnekte session scope olan userDetails nesnesi singleton scope olan rentalService nesnesine enjekte edilmektedir. Burada nasıl bir sorun mevcuttur?

<bean id=”userDetails”

class=”com.kurumsaljava.spring.UserDetails” scope=”session”/>

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServicelmpl”>

<property name=”userDetails” ref=”userDetails”/>

</bean>

Singleton olan nesneler Application Context oluştuğunda Spring sunucusu tarafından sadece bir kere yapılandırılırlar. Yukarıda yer alan örnekte singleton olan rentalService nesnesine session scope sahibi userDetails enjekte edilmektedir. rentalService nesnesi oluşturulduğu esnada Application Context bünyesinde userDetails isminde bir nesne olamaz, çünkü böyle bir nesne kullanıcının bir web oturumu (HttpSession) açmasıyla var olabilir. Bu yüzden singleton olan rentalService nesnesine session scope olan bir nesne enjekte edilmesi mümkün değildir. Kısaca burada uygulamanm ilerleyen bir safhasında oluşturulacak bir nesne var oluşunun çok öncesinde mevcut bir nesneye enjekte edilmeye çalışılmaktadır ki bu mümkün değildir.

Bu sorunu userDetails nesnesine vekillik edecek bir nesne oluşturup, bu vekil nesneyi rentalService nesnesine enjekte ederek çözebiliriz. Vekil nesne rentalService tarafından kullanıldığında, vekil olduğu nesneyi içinde buludugu scopedan alarak, rentalService nesnesine verecektir.

Bu gibi durumlarda kullanılmak üzere vekil nesne oluşturmak için aop isim alanında yer alan scoped-proxy elementi kullanılabilir.

<bean id=”userDetails”

class=”com.kurumsaljava.spring.UserDetails” scope=”session”>

<aop:scoped-proxy/>

</bean>

aop:scoped-proxy elementi kullanıldığında Spring sunucusu CGLIB kütüphanesi yardımıyla bir vekil nesne oluşturur. userDetails nesnesinin enjekte edildiği her nesneye bu vekil nesne enjekte edilmiş olur, çünkü vekil nesne userDetails nesnesinin sahip olduğu smıfı genişletmektedir. Bu vekil nesne userDetails nesnesine yöneltilen tüm istekleri karşılar. Kullanılan scope türüne göre vekil nesne vekil olduğu nesneyi ait olduğu scopedan alarak, kullanıcı nesnenin geçerli nesne üzerinde işlem yapmış olmasını sağlar.

scoped-proxy aşağıdaki şekilde tanımlandığında Spring sunucusu CGLIB yerine JDK interface bazlı dinamik vekil oluşturma mekanizmasını kullanır. Bu durumda mutlaka vekil olunan nesnenin bir interface smıfı implemente etmiş olması gerekmektedir. Sadece bu durumda vekil nesneler oluşturulabilir.

<aop:scoped-proxy proxy-target-class=”false”/>

Tanımlanabilir (Custom) Bean Scope

Spring tarafından kullanılan bean scope mekanizması genişletilebilir yapıdadır, singleton ve prototype bean scopelar harici mevcut bean scopeları değiştirebilir ya da kendi bean scopelarımızı oluşturabiliriz. Yeni bir bean scope oluşturmak için org.springframeworkbeans.factory.config. Scope interface sınıfını implemente eden bir alt sınıf oluşturmamız gerekmektedir. Yeni bir scope oluşturma işlemini bir örnek üzerinde yakından inceleyelim.

Kod 2.9.1 de ThreadScope ismini taşıyan yeni bir scope smıfı yer almaktadır. Bean tanımlaması yaparken scope=thread kullanılarak oluşturulan nesnelerin ömürlerini bir threadin ömrü ile sınırlı tutmak istiyoruz. Bu yeni scope tanımlaması kullanıldığı taktirde oluşturulan nesneler kullanılan thread hayatta olduğu sürece kullanımda olacaktır. Threadin son bulmasıyla sahip olduğu nesneler yok edilir.

Kod 2.9.1 – ThreadScope

package com.kurumsaljava.spring.scope;

import java.util.HashMap; import java.util.Map;

import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.Scope; import org.springframework.core.NamedThreadLocal;

public class ThreadScope implements Scope {

private final ThreadLocal<Map<String, Object» threadScope = new NamedThreadLocal<Map<String, Obj ect»(

“ThreadScope”) {

@Override

protected Map<String, Object> initialValue() { return new HashMap<String, Obj ect>();

}

@Override

public Object get(String name, ObjectFactory objectFactory) { Map<String, Object> scope = threadScope.get();

Object object = scope.get(name); if (object = null) {

object = objectFactory.getObject(); scope.put(name, object);

}

return object;

}

@Override

public Object remove(String name) {

Map<String, 0bject> scope = threadScope.get(); return scope.remove(name);

}

@Override

public void registerDestructionCallback(String name,

Runnable callback) {

@Override

public Object resolveContextualObject(String key) { return null;

@Override

public String getConversationld() {

return Thread.currentThread().getName();

}

Oluşturduğumuz yeni scope sınıfını Spring’e tanıtmamız gerekiyor. Bu amaçla kod 2.9.2 de yer aldığı gibi CustomScopeConfigurer sınıfının sahip olduğu scopes isimli listeye thread ismi altmda ThreadScope sınıfını ekliyoruz.

Kod 2.9.2 – applicationContext.xml <bean

class=”org.springframework.beans.factory.config.

CustomScopeConfigurer”>

<property name=”scopes”>

<map>

<entry key=”thread”>

<bean

class=”com.kurumsaljava.spring.scope.

ThreadScope”/>

</entry>

</map>

</property>

</bean>

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServicelmpl” s cope=”thread”>

<property name=”customerRepository”

ref=”customerRepository” />

<property name=”rentalRepository”

ref=”rentalRepository” />

</bean>

Spring scope-thread ile karşılaştığı yerlerde ThreadScope sınıfının get() metodu üzerinden talep edilen nesneyi oluşturup bir ThreadLocal içindeki listeye (Map) ekleyecektir. Bu liste içinde yer alan nesneler tekrar oluşturulmadan kullanıcıya geri verilir.

Metot Enjeksiyonu

Spring’in varsayılan nesne oluşturma ayarmın singleton yani tekil nesne olduğunu gördük. Tekil nesneler Spring tarafmdan bir kez oluşturulur ve kullanıma sunulur. Bu sebepten dolayı tekil olan bir nesneye prototype tipinde olan bir nesneyi devamlı enjekte etmek mümkün değildir, çünkü bağımlılığın enjekte edilmesi işlemi nesne oluşturulurken bir kez yapılan bir işlemdir. Prototype tipinde olan nesneler Spring tarafmdan devamlı yeniden oluşturulur, ama böyle bir nesneye bağımlılık duyan bir tekil nesne sürekli yeni prototype nesneyi enjeksiyon yöntemiyle edinemez, çünkü Spring tekil nesnelere oluşturulma süreçlerinden sonra bağımlılıkların enjeksiyonu konusunda ilgi göstermez.

Kod 2.9.3 de yer alan örnekte Singleton nesnesine prototype nesnesi konstrüktör üzerinde enjekte edilmektedir. Singleton sınıfının Spring konfigürasyon dosyasında tekil, Prototype sınıfının prototype nesne olarak tanımlandığını düşünelim. Application Context oluştuktan sonra Spring bir defaya mahsus olmak üzere Singleton sınıfından olan tekil nesneye prototype değişkenini enjekte edecektir. Bu işlemin ardmdan Singleton sınıfından olan tekil nesnenin yeni bir prototype nesnesi edinmesi imkansızdır. Bu sorunu çözmek için metot enjeksiyonu yöntemini kullanabiliriz. Spring konstrüktör ve set() metotları bazlı enjeksiyon yanı sıra, mevcut bir smıf metodunu değiştirerek, smıfa yeni bir davranış biçimi kazandırmak için kullanılabilecek metot enjeksiyonu yöntemini sunmaktadır. Kod 2.9.3 – Singleton

public class Singleton {

private Prototype prototype;

public Singleton(Prototype prototype) { this.prototype = prototype;

}

public void doSomething() { prototype.foo();

}

Tekil bir nesneye ihtiyaç duyduğu prototype tipinde bir nesneyi verebilmek için prototype nesne edinme işlemini soyut bir metot olarak tanımlayabiliriz. Kod

2.9.4 de yer alan örnekte Singleton sınıfına prototype tipindeki nesneye konstrüktör aracılığı ile enjekte etmek yerine, createPrototype() isminde soyut bir metot tanımlıyoruz. createPrototype() metodun soyut metot olarak tanımlanabilmesi için Singleton sınıfının da soyut olarak tanımlanması gerekmektedir. Bu şartlar altında Spring’in Singleton sınıfından yeni bir nesne oluşturamayabileceğini düşünebilirsiniz. Metot enjeksiyon yöntemiyle bu mümkün.

Kod 2.9.4 – Singleton public abstract class Singleton { private Prototype prototype;

public Singleton() {

}

public void doSomething() { createPrototype().foo() ;

}

protected abstract Prototype createPrototype();

}

Metot enjeksiyonu yöntemi kullanıldığında Spring CGLIB kütüphanesini kullanarak Singleton sınıfından olma yeni bir altsınıf oluşturur. Dinamik olarak oluşturulan bu altsınıf soyut olan createPrototype() metodunu implemente eder. Bu implementasyon tekil nesneye yeni bir prototype nesneyi kullanma fırsatı tanır. Bu şekilde tekil nesneye dolaylı olarak bir prototype nesne enjekte edilmiş olur. Bu işlemi gerçekleştirmek için kullanılan yöntem metot enjeksiyonudur. Kod 2.9.5 de metot enjeksiyonu yöntemini kullanmak için gerekli Spring konfigürasyonu yer almaktadır, lookup-method elementi ile değiştirilmesi yani dinamik olarak implemente edilmesi gereken metot ismi tanımlanmaktadır.

Kod 2.9.5 – app-config.xml

<bean id=”prototype”

class=”com.kurumsaljava.spring.Prototype” scope=”prototype”/>

<bean id=”singleton”

class=”com.kurumsaljava.spring.Singleton”>

<lookup-method name=”createPrototype” bean=”prototype”/>

</bean>

Dinamik olarak bir altsınıfın oluşturulabilmesi için tekil nesnenin ait olduğu sınıfın ve implemente edilen metodun final olmaması gerekmektedir. Bunun yanı sıra tekil nesnenin ait olduğu sınıf soyut olarak tanımlandığı için, bu sınıfı test edebilmek için bir altsınıfın oluşturulması gerekmektedir. Ayrıca metot enjeksiyon yöntemiyle oluşturulan altsınıflar üzerinde serialization işlemi yapılamaz. Spring 3.2 ile CGLIB kütüphanesinin classpath içinde olma zorunluluğu bulunmamaktadır, çünkü bu kütüphanede yer alan sınıflar org.springframework paketine alınmıştır.

Metot Değiştirme Yöntemi

replaced-method konfigürasyon elementini kullanarak bir nesnenin sahip olduğu metot yerine başka bir nesnenin sahip olduğu metodu koşturabiliriz. Bu yönteme method overriding ismi verilmektedir. Nasıl altsınıflar üstsınıflarda yer alan metotları @Override anotasyonunu kullanarak yeniden yapılandırabiliyorlarsa, Spring’de mevcut bir metodu başka bir metotla değiştirebilmekte ve nesneye yeni bir davranış biçimi katabilmektedir. Bu metot değiştirme mekanizması da Spring tarafından kullanılan metot enjeksiyon yöntemiyle sağlanmaktadır.

Kod 2.9.5 de yer alan örnekte koşturmak istediğimiz metot doA() metodudur.

Kod 2.9.5 – AClass

public class AClass {

public String doA(String a) {

System.out.println(a); return a;

}

Kullanılacak yeni metodu tanımlamak için

org.springframework.beans.factory.support.MethodReplacer sınıfını implemente eden yeni bir sınıf oluşturmamız gerekmektedir. Spring’in doA() yerine koşturacağı metot kod 2.9.6 da ye alan reimplement) metodudur.

Kod 2.9.6 – ReplacerClass

public class ReplacerClass implements MethodReplacer {

public Object reimplement(Object o, Method m, Object[] args)

throws Throwable {

// args[0] doA() metodunda yer alan parametredir.

String input = (String) args[0];

return …;

}

r

i

Gerekli konfigürasyon kod 2.9.7 de yer almaktadır, replaced-method elementi ile orijinal metot ve bu metodun yerine geçecek yeni metot tanımlanmaktadır, arg­type elementi ile yeni metot bünyesinde kullanılacak orijinal metot parametreleri tanımlanmaktadır.

Kod 2.9.7 – app-config.xml

<bean id=”aClass” class=”com.kurumsaljava.spring.AClass”> <replaced-method name=”doA” replacer=”replacer”> <arg-type>String</arg-type>

</replaced-method>

</bean>

<bean id=”replacer” class=”com.kurumsaljava.spring.ReplacerClass”/>

Fabrika Metodu

Her sınıfın kullanıma açık sınıf konstrüktörü olmayabilir. Bu durum genelde tekil (singleton) nesneler için geçerlidir. Bir sınıftan birden fazla nesne üretimini engellemek için sınıf konstrüktörleri private olarak işaretlenir. Bu tür sınıflardan new kullanılarak nesne üretilmesi mümkün değildir, bean elementinin factory- method özelliği aracılığı ile tekil bir nesnenin Spring ile kullanımı mümkündür.

Kod 2.10 – DBSingleton

package com.kurumsaljava.spring; import java.sql.Connection; public class DBSingleton {

private static final DBSingleton instance = new DBSingleton(); private DBSingleton() {

}

public static final DBSingleton getlnstance() { return instance;

}

public Connection getConnection() { return null;

}

Normal şartlar altında kod 2.10 da yer alan DBSingleton sınıfının kullanımı

DBSingleton.getlnstance().getConnection() ;

şeklinde olacaktır. Bu sınıfı bir Spring nesnesi olarak tanımlayıp, kullanmak istersek, factory-method özelliği bu sınıfın tekil nesnesini kullanmamızı mümkün kılacaktır.

<bean id=”dbSingleton”

class=”com.kurumsaljava.spring.DBSingleton” factory-method=”getInstance” />

factory-method kullanılarak tanımlanan sınıfın static olması gerekmektedir. Bu tanımlamanın ardından

DBSingleton dbSingletion = (DBSingleton) ctx.getBean(“dbSingleton”) ; Connection connection = dbSingletion.getConnection();

şeklinde DBSingleton’ın ihtiva ettiği tekil nesneyi kullanabiliriz.

Fabrika Sınıfları

Bir Spring nesnesi tanımlaması yaparken class element özelliğinden faydalandık. Bu Spring’e hangi sınıfı kullanarak bir nesne oluşturması gerektiği bilgisini vermektedir, class ve factory-method element özellikleri harici factory-bean element özelliği kullanılarak ta bir Spring nesnesi tanımlaması yapılabilir, factory-bean kullanıldığı taktirde, bir POJO (Plain Old java Object) smıfı nesneleri üreten fabrika (factory) olarak kullanılır.

<bean id=”customerRepositoryFactory”

class=”com.kurumsaljava.spring.CustomerRepositoryFactory” />

<bean id=”CustomerRepository”

factory-bean=”CustomerRepositoryFactory” f a cto ry-method=”getNewInstance”>

</bean>

Bir önceki kod bloğunda görüldüğü gibi CustomerRepository Spring nesnesi tanımlamasında class yerine factory-bean ve factory-method element özellikleri kullanılmıştır. Böyle bir konfigürasyonda Spring factory-bean ile tanımlanan fabrika sınıfının factory-method ile tanımlanan metodu ile bir CustomerRepository nesnesi oluşturur. Kullanılan fabrika sınıfı CustomerRePositoryFactory aşağıda yer almaktadır. Burada nesneyi oluşturma sorumluluğu tamamen factory-bean ile tanımlanan smıfa aittir.

package com.kurumsaljava.spring;

public class CustomerRepositoryFactory {

public CustomerRepository getNewInstance() { return new CustomerRepositorylmpl();

}

Factory Bean Interface Sınıfı

Spring’in nesne oluşturma ve enjekte etme metotları sadece fabrika metodu ve fabrika sınıfları ile sınırlı değildir. Spring’in bir parçası olan FactoryBean interface sınıfı kullanılarak da nesne oluşturma ve enjekte etme işlemleri yapılabilir.

Kod 2.10.1 CustomerRepositoryFactoryBean package com.kurumsaljava.spring;

import org.springframework.beans.factory.FactoryBean; public class CustomerRepositoryFactoryBean implements FactoryBean<CustomerRepository> {

public CustomerRepository getNewInstance() { return new CustomerRepositorylmpl();

}

@Override

public CustomerRepository getObjectO throws Exception { return new CustomerRepositorylmpl();

}

@Override

public Class<?> getObjectType() {

return CustomerRepository.class;

}

@Override

public boolean isSingleton() { return true;

}

FactoryBean interface sınıfında implemente edilmesi gereken üç metot bulunmaktadır. getObject() metodu tanımlanan sınıftan bir nesne oluşturur. getObjectType() metodu hangi sınıfın nesneyi oluşturmak için kullanılacağını tayin eder. isSingleton() metodu true değerini geri verirse, Spring tarafmdan tekil bir nesne oluşturulur. Bu değer false ise, Spring her istekte yeni bir nesne oluşturur.

RentalServicelmpl sınıfından bir nesneye CustomerRepositorylmpl sınıfından bir nesneyi enjekte etmek için CustomerRepositoryFactoryBean (kod 2.10.1) isimli, FactoryBean interface sınıfını implemente eden bir fabrika smıfı oluşturmuş olduk. Bu fabrika sınıfını aşağıdaki şekilde Spring XML dosyasında bir customerRepository nesnesi oluşturmak ve rentalService nesnesine enjekte etmek için kullanabiliriz.

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServiceImpl”>

<property name=”customerRepository”

ref=”customerRepository” />

<property name=”rentalRepository”

ref=”rentalRepository” />

</bean>

<bean id=”customerRepository”

class=”com.kurumsaljava.spring.CustomerRepositoryFactoryBean” />

Bu örnekte görüldüğü gibi customerRepository isimli Spring nesnesi tanımlamasında class olarak FactoryBean interface sınıfını implemente eden CustomerRepositoryFactoryBean sınıfını kullandık. Böyle bir konfigürasyonda Spring CustomerRepositoryFactoryBean sınıfının getObject() metodunu kullanarak yeni bir CustomerRepositorylmpl nesnesi oluşturacaktır. Eğer Spring isSingleton() metodundan true değerini geri alırsa, bu durumda sadece bir defaya mahsus getObject() metodunu kullanarak bir nesne oluşturur. Oluşturduğu nesneyi hafızada tutarak, tekil bir nesne olmasını sağlar ve bu nesneyi her defasmda kullanıma sunar. isSingletion() metodunun false değerini geri vermesi durumunda Spring her defasmda getObject() metodu üzerinden yeni bir nesne oluşturur.

@Component anotasyonu kullanılmadığı taktirde enjekte edilmek istenen nesnelerin XML konfigürasyon dosyasında Spring nesnesi olarak tanımlanması zorunludur. Karmaşık yapıdaki nesnelerin XML konfigürasyon dosyasmda

Spring nesnesi olarak tanımlanmaları zor olabilir. Bu gibi durumlarda FactoryBean interface sınıfını implemente eden bir fabrika smıfı oluşturulabilir. Karmaşık nesne oluşturma işlemi bu şekilde getObject() metoduna taşınarak bir metot bünyesinde gerçekleştirilmiş olur. Bu işlemin bir Java metodunda yapılması, bu kod biriminin tekrar kullanılabilirlik oranını ve şansmı artırır.FactoryBean interface sınıfını implemente eden sınıflar Spring tarafmdan nesne üretici fabrika sınıfları olarak otomatik olarak keşfedilir ve kullanılır.

CustomerRepositoryFactoryBean tarafmdan oluşturulan nesneye

context.getBean(“CustomerRepository”);

şeklinde ulaşabiliriz. CustomerRepositoryFactoryBean sınıfından olan, yani fabrika nesnesine erişmek için & işaretinin şu şekilde kullanılması gerekmektedir.

context.getBean(“ScustomerRepository”);

Bu bize doğrudan fabrika nesnesini verir.

Sirküler Bağımlılıklar

Aşağıda yer alan örnekte servicel ve service2 arasında sirküler (cyclic) bağımlılık bulunmaktadır, serverl nesnesini oluşturmak için service2, service2 nesnesini oluşturmak için servicel nesnesine ihtiyaç duyulmaktadır.

<bean id=”serverl”

class=”com.kurumsaljava.spring.service.MyService”>

<constructor-arg name=”servicel” ref=”server2″/>

</bean>

<bean id=”server2″

class=”com.kurumsaljava.spring.service.MyService”>

<constructor-arg name=”servicel” ref=”serverl”/>

</bean>

Spring böyle bir sirküler bağımlılık keşfettiğinde BeanCurrentlyInCreationException hatasını fırlatır. Bu sorunu aşmanm bir yöntemi bağımlılıkları set() metotları aracılığı ile enjekte etmektir. Genel olarak sirküler bağımlılıklar bakımı zor olduğundan, bu yapıların çözülmelerinde fayda vardır.

Bağımlılıkların Enjekte Edilmesi Yönteminin Avantajları

Spring çatısının sunduğu bağımlılıkların enjekte edilmesi yönetiminin yazılımcı ve uygulama için sağladığı avantajlar şunlardır:

• Interface sınıflarının kullanımını teşvik eder. Bu yazılımcının uygulamayı bağımlılıkların tersine çevrilmesi (DIP – Dependency Inversion Principle) prensine uygun geliştirmesini sağlar.

• Uygulamanın hazır, konfigüre edilmiş nesneleri kullanmasını sağlar. Bağımlılıkların yazılımcı tarafından programlanmasını engeller.

• Kodu basitleştirir ve bakımını ve geliştirilmesini kolaylaştırır.

• Uygulamanın test edilmesini kolaylaştırır. Bağımlılıkları oluşturan nesneler yerine test amaçlı sahte nesne implementasyonları (stub ya da mock object) kullanımını mümkün kılar.

• Nesnelerin yaşam döngüsünü merkezi bir yerden kontrol etmeyi sağlar.

Bağımlılıkları Enjekte Ederken Hangi Yöntem Kullanılmalı?

Spring çatısında bağımlılıkları konstrüktör ya da set() metotları aracılığı ile enjekte edebileceğimizi gördük. Hangi yöntemi kullanmalıyız sorusu aklınıza gelmiş olabilir. Bu soruya açıklık getirmek isterim.

Her iki yöntemi de birlikte kullanmak mümkündür. Konstrüktör parametreleri zaman içinde artabileceği için konstrüktör aracılığı ile yapılan enjeksiyon karmaşık hale gelebilir. Bu yüzden benim tavsiyem set() metotlarını kullanarak bu işlemi gerçekleştirmektir. @Required anotasyonu kullanılarak, set() metotları aracılığı ile bağımlılıkların enjekte edilmesi zorunlu hale getirilebilir. Bunun yanı sıra altsınıflar otomatik olarak public ve protected olan set() metotları miras alırlar ve altsınıflara herhangi yeni bir metot tanımlama zorunluluğu olmadan nesneler enjekte edilebilir.

Yazılımcının kontrolü dışındaki sınıfların set() metotları olmayabilir. Bu durumda geriye sadece konstrüktör aracılığı ile enjeksiyon seçeneği kalmaktadır.

Bunun yanı sıra Konstrüktör bazlı enjeksiyonda bir nesne için tüm bağımlılıkları nesne oluşturma aşamasında doğrudan enjekte edildiğinden, kullanıcıya verilen nesne tam teşekküllü yapıda olacaktır. Final olan değişkenlere konstrüktör aracılığı ile enjeksiyon yapılabildiği için bu tür oluşturulan nesneler değiştirilemez (immutable) yapıdadır. Bunun gerekli olduğu durumlarda seçim konstrüktör bazlı enjeksiyon olmalıdır.

Spring’in Motoru Nasıl Çalıştırılır?

Spring’in iç organları sahip olduğu sınıflar ise, nefes alıp, vermesini sağlayan XML konfigürasyon dosyasıdır. Böyle bir XML dosyası Spring uygulamasının nasıl yapılandırılması gerektiğini ihtiva eder. Kullandığımız Araç kiralama servisi örneğinde applicationContext.xml isminde böyle bir Spring XML konfigürasyon dosyası oluşturmuştuk. Bu dosyanm kullanılışını ve Spring uygulamasmm nasıl ayağa kaldırıldığını kod 2.7 de incelemiştik.

Bir Spring uygulaması değişik ortamlarda çalışır hale getirilebilir. Bunlar:

• JUnit testleri

• Web uygulamaları

• Kurumsal Java uygulamalar (EJB)

• Tek başına (standalone) çalışan uygulamalar

Spring’in motorunun çalıştırılabilmesi için XML konfigürasyon dosyasmın uygulama tarafmdan yüklenebilmesi gerekir. XML konfigürasyon dosyası değişik lokasyonlardan yüklenebilir. Bunlar:

• classpath

• sistemin herhangi bir dizini

• ortama ilişkin bir dizin (environment relavite path, örneğin web uygulamasmm bir dizini)

Motorun çalışmasıyla birlikte Spring hafızada Application Context (resim 2.5) ismini taşıyan bir sunucu (container) oluşturur. Bu sunucuyu XML konfigürasyon dosyasınm hafızadaki hali olarak düşünebiliriz. Singleton (tekil) olarak tanımlanmış tüm nesneler Spring tarafmdan oluşturularak sunucu içine konuşlandırılır. Singleton olmayan nesneler örneğin getBean() metodu aracılığı ile talep edildiklerinde, Spring tarafmdan gerekli bağımlılıklar enjekte edilerek kullanıcıya verilir.

XML Konfigürasyon Dosyasının Yüklenmesi

Bir Spring uygulamasının çalışır hale gelebilmesi için Spring nesnelerinin tanımlandığı XML dosyasmın bulunması ve yüklenmesi gerekir demiştik. Kod

2.7 de kullandığımız Main sınıfı ClassPathXmlApplicationContext aracılığı ile classpath için bulunan applicationContext.xml dosyasını bularak, yüklemiş ve bir Application Context oluşturmuştu. XML konfigürasyonun classpath içinde bulunmadığı durumlarda FileSystemXmlApplicationContext kullanılabilir.

Kod 2.11 – FileSystemXmlApplicationContext Kullanımı

package com.kurumsaljava.spring;

import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;

import org.springframework.context.ApplicationContext; import org.springframework.context.support.

FileSystemXmlApplicationContext;

public class Main {

public static void main(String[] args) throws Exception { ApplicationContext ctx =

new FileSystemXmlApplicationContext(

“C:/resources/applicationContext.xml”) ;

RentalService rentalService =

(RentalService) ctx.getBean(“rentalService”);

Rental rental = rentalService.rentACar(“Özcan Acar”, Car(“ford”, “fiesta”), getRentalBegin() , getRentalEnd());

System.out.println(“Rental status: ” + rental.isRented());

System.out.println((CustomerRepository)

ctx.getBean(“CustomerRepository”));

}

private static Date getRentalEnd()

throws ParseException { return new SimpleDateFormat(“dd/MM/yy”)

}

private static Date getRentalBegin()

throws ParseException { return new SimpleDateFormat(“dd/MM/yy”).

parse(“22/12/2013”);

}

Kod 2.11 de bulunan Main sınıfı FileSystemXmlApplicationContext sınıfını kullanarak C:\resource\applicationContext.xml lokasyonunda bulunan applicationContext.xml dosyasını yüklemektedir.

Web uygulamalarında XML konfigürasyon dosyalarını yüklemek için XmlWebApplicationContext smıfı kullanılabilir. Bu sınıfın nasıl kullanıldığını ilerleyen bölümlerde birlikte inceleyeceğiz.

classpath içinde bulunan birden fazla konfigürasyon dosyasmı yüklemek için joker işareti olarak bilinen kullanılabilir.

ApplicationContext ctx =

new ClassPathXmlApplicationContext(“conf/*-config.xml”);

Yukarıda yer alan tanımlama ile conf dizininde bulunan ve -config terimini ihtiva eden tüm konfigürasyon dosyaları Application Context’i oluşturmak için yüklenir.

Konfigürasyon dosyalarının hangi kaynaklardan yüklendiğini ifade etmek için classpath, file ve http gibi kısaltmalar kullanılabilir, örneğin biri classpath içinde bulunan ve bir diğeri c:\resource dizinindeki iki konfigürasyon dosyası aşağıda yer alan kod satırmda olduğu gibi yüklenebilir.

ApplicationContext ctx = new ClassPathXmlApplicationContext(

“classpath:applicationContext.xml”,

“file:C:/resources/test-datasource.xml”);

ClassPathXmlApplicationContext classpath içinde yer alan konfigürasyon dosyalarını yüklemek için kullanılırken, file: kısaltması herhangi bir dizinde yer alan konfigürasyon dosyasmı adreslemewk için kullanılabilmektedir.

Eğer kullanmak istediğimiz konfigürasyon dosyası classpath ya da sistemdeki bir dizin içinde değilse, http: kısaltması kullanılarak bir konfigürasyon dosyasmı bir uygulama sunucusundan edinebiliriz.

ApplicationContext ctx = new ClassPathXmlApplicationContext(

“http://ip:port/applicationContext.xml”);

Çoklu XML Konfigürasyonu

Birden fazla XML dosyası kullanılarak bir Application Context oluşturulabilir. Bu şekilde Spring nesnelerini mantıksal guruplara ayırmak mümkündür. Çoğu zaman bu mekanizma uygulamanın servis katmanında kullanılan Spring nesneleri ile altyapı katmanında kullanılan Spring nesnelerini birbirlerinden bağımsız olarak, ayrı XML dosyalarmda tanımlamak için kullanılır. Her ortama göre kullanılan altyapı komponentleri değişik olacağmdan, böyle bir ayrıştırma servis katmanı konfigürasyonunun değişik altyapı konfigürasyonları ile kombine edilerek kullanılmasını mümkün kılar.

Araç kiralama servisi uygulaması için böyle bir ayrıma gitseydik, konfigürasyonumuz nasıl olurdu? Bu sorunun cevabı bir sonraki kod bloklarında yer almaktadır.

Kod 2.12 – applicationContext.xml <?xml version=”l.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=” http://www.springframework.org/schema/ beans

http://www.springframework.org/schema/beans/ spring-beans-3.0.xsd”>

<bean id=”rentalService”

class=”com.kurumsaljava.spring.RentalServicelmpl” scope=”prototype”>

<property name=”CustomerRepository”

ref=”CustomerRepository” />

<property name=”rentalRepository”

ref=”rentalRepository” />

</bean>

<bean id=”rentalRepository”

class=”com.kurumsaljava.spring.

RentalRepositorylmpl”> <property name=”dataSource” ref=”dataSource” /> </bean>

<bean id=”customerRepository”

class=”com.kurumsaljava.spring.

CustomerRepositoryImpl”> <property name=”dataSource”

ref=”dataSource” />

</bean>

</beans>

Kod 2.13 – test-datasource.xml

<?xml version=”l.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/

spring-beans-3.0.xsd”>

<bean id=”dataSource”

class=”com.kurumsaljava.spring.DummyDataSourceImpl”/>

</beans>

Kod 2.14 – Main

public static void main(String[] args) throws Exception {

ApplicationContext ctx =

new ClassPathXmlApplicationContext(“applicationContext.xml”, “test-datasource.xml”);

RentalService rentalService =

(RentalService) ctx.getBean(“rentalService”);

Rental rental =

rentalService.rentACar(“Özcan Acar”, new Car(“ford”, “fiesta”), getRentalBegin(), getRentalEnd());

System.out.println(“Rental status: ” + rental.isRentedO);

System.out.println((CustomerRepository)

ctx.getBean(“customerRepository”));

}

Servis katmanında yer alan rentalService, customerRepository ve rentalRepository sınıfları için applicationContext.xml isminde bir konfigürasyon dosyası (kod 2.12) oluşturduk. Şimdiye kadar kullandığımız RentalRepositorylmpl ve CustomerRepositorylmpl sınıfları herhangi bir veri tabanı işlemi yapma özelliğini sahip değiller. Bu sınıfların veri tabanı işlemlerini gerçekleştirebilmeleri için DataSource ismini taşıyan bir interface sınıf tanımlıyoruz. Kod 2.12 de yer alan Spring nesne tanımlamaları ile rentalRepository ve customerRepository nesnelerine datasource ismini taşıyan bir nesne enjekte edilmektedir. Nesneler arasındaki oluşturmak istediğimiz bağlantı resim 2.8 de yer almaktadır.

Resim2.8 Resim 2.8

Uygulamanın geliştirilmesi için kullanılan veri tabanı sistemi ile, uygulama sunucuları üzerinde çalışırken kullanılan veri tabanı sistemi değişik türde olabilir. Bu tür değişiklikleri uygulamadan saklamak amacıyla DataSource tarzı interface sınıflar kullanılır. Bu interface sınıfın değişik ortamlara göre implemente edilmesi gerekmektedir, örneğin oluşturduğumuz birim testlerini koşturmak için DummyDataSourcelmpl isminde gerçek bir veri tabanı sistemini kullanmayan bir implementasyon oluşturabiliriz. Bu implementasyon birim testlerini koşturmak için gerekli verileri veri tabanından edinmişcesine birim testine verebilir. Uygulamanın gerçek sunucularda bir Oracle veri tabanı sistemi ile çalışmasını sağlamak amacıyla OracleDataSourcelmpl implementasyonu oluşturulabilir.

Eğer dataSource tanımlamasını applicationContext.xml dosyasında yapmış olsaydık, uygulamanın çalıştığı ortama göre kullanılan DataSource implementasyonunu bu dosya üzerinde değiştirmek zorunda kalırdık. Bunu önlemek amacıyla kod 2.13 de yer aldığı gibi test-datasource.xml ismini taşıyan yeni bir XML konfigürasyon dosyası oluşturuyoruz. applicationContext.xml ve test-datasource.xml dosyaları kod 2.14 de yer aldığı gibi ClassPathXmlApplicationContext aracılığı ile kombine edilebilmektedir. Bu uygulamayı geliştirmek için kullanabileceğimiz bir Application Context oluşturur. Uygulamayı müşterimiz için çalışır hale getirmek istediğimizde datasource.xml isminde, OracleDataSourcelmpl sınıfını kullanan yeni bir konfigürasyon dosyası oluşturabilir ve ClassPathXmlApplicationContext üzerinden applicationContext.xml dosyasını bu konfigürasyon dosyası ile kombine ederek, uygulamayı bir Oracle veri tabanını kullanacak şekilde konfigüre edebiliriz.

Çoklu XML konfigürasyon imkanı uygulamayı tanımlanmış parçalara bölerek, bu parçaları değişik ortamlarda kombine etmemizi ve ortama uygun bir Spring uygulaması oluşturmamızı mümkün kılmaktadır. Uygulamayı oluşturan bu konfigürasyon dosyaları aynı kod birimlerinde olduğu gibi tekrar kullanımı teşvik etmekte ve uygulamanın modüler bir yapıda olmasını sağlamaktadır.

Okul için hazırladığım Sanallaştırma ödevimi paylaşmak isterim.

ÖZET

Dünyada enerji fiyatlarının artışı, küresel ısınma ve çevre kirliliği hususlarının her geçen gün daha çok karşımıza çıkmakta, hatta göz ardı edilmesine daha fazla müsamaha göstermeyecek biçimde kendini hissettirmektedir. Bu durumla birlikte çözüm arayışları da özellikle orta ve büyük işletmelerin aksiyon planlarında yer almaya başlamıştır. Hızlı büyüme, artan enerji ve gayrimenkul giderleri günümüz iş dünyasının karşı karşıya olduğu zorluklardır. Geçmiş yıllarda yaşamış olduğumuz küresel krizin de etkisiyle kurumlar, BT altyapılarını sadeleştirerek ve kaynaklarını daha verimli kullanarak iş hızlarını arttırmak için çözümler aramaktadırlar.

Günümüzde sunucu, istemci gibi bilgi teknolojilerini ilgilendiren her konuda sanallaştırmanın yaygınlaşması ve uygulamaların webde uygulanabilir hale gelmesiyle bulut bilişimin temellerini oluşturmuştur.

Sanallaştırma kullanılması ile kurumlarda kullanılan fiziksel sunucu sayıları azaltılmakta, daha az makine ile daha çok iş yapılabilmesine imkan sağlanmakta, yani kaynakların verimliliği arttırılabilmektedir. Daha az fiziksel donanım kullanılması ile satın alma, enerji başta olmak üzere oldukça tasarruf mümkün hale gelmektedir. İşletim sistemi geçişleri, uygulamalarının yeni sürümlerinin devreye alınması pratik olarak tabii uzman kişilerce gerçekleştirilebilmektedir. Tek bir ara yüzden fiziksel ve sanal ortamlar manage edilebilmektedirler. Yapılacak planlı çalışma öncesinde sunucunun anlık görüntüsü (image, backup) alınarak çalışmadan kaynaklanan herhangi bir sorun çıkması durumunda birkaç dakika içerisinde önceki durumuna dönülebilmektedir. Fiziksel sunucularımızda çalışma yapılması gerektiğinde sunucunun bakım moduna alınması ile üzerindeki iş yükleri diğer sunuculara kaydırılarak hizmet kesintisi yaşamadan çalışma yürütülebilmektedir. LOAD BALANCE teknolojisiyle yükler dağıtılabildiği gibi cluster sunucular sayesinde felaket durumunda veri merkezindeki sistemler otomatik olarak felaket kurtarma merkezinden çalışmaya devam edilebilmesini sağlarlar (disaster recovery).

SANALLAŞTIRMA (VIRTUALIZATION)

Sanallaştırma kavramı temel olarak donanım, yazılım, uygulama, ağ, depolama gibi farklı katmanlardaki kaynakları birbirinden izole ederek kullanılmasını sağlayan yazılım teknolojisi olarak tanımlanabilir.

Sanallaştırma sunucu, işletim sistemi, depolama cihazı gibi tek bir fiziksel kaynağı çok sayıda mantıksal kaynakmış gibi çalıştırabileceği gibi birden çok fiziksel kaynağı da tek bir mantıksal kaynak olarak da çalıştırabilmektedir.

Başlangıçta amaç kullanılmayan kaynakları geri kazanıp aynı anda birden fazla işletim sistemini tek bir fiziksel sistem üzerinde çalıştırmak iken günümüzde artık neredeyse her katmanda sanallaştırma teknoloji çözümleri bulunmaktadır.

TARİHSEL SÜRECİ

Sanallaştırmanın temelleri son yıllarda değil oldukça gerilere daynmaktadır. Sanallaştırma düşüncesi ilk kez 1950’lerde tartışılmaya başlanmıştır. 1960’ların başlarında IBM sanallaştırmanın arkasındaki asıl itici güç olan Time Sharing Computing’i tanıtmıştır. 1970’lerde mainframe bilgisayarlar bir 4 işletim sisteminin birden fazla oturumunu aynı anda, her birini birbirinden bağımsız olarak çalıştırmayı başarabilmiştir.

Bir ana bilgisayar ve çok sayıda terminalden oluşan ilk bilgisayar sistemlerinde kullanılan yapı sanallaştırma için en güzel örneklerden biridir. Her bir kullanıcı kendi önündeki terminali kullanarak işlem yapmakta input sağlayıp output görmekte, ancak işlemler tek bir ana bilgisayar üzerinde o kullanıcıya ayrılmış bir alanda gerçekleşmektedir.

Sanallaştırmanın en çok bilinen örneği “Java Sanal Makinesi”dir. Java Sanal Makinesi’nin amacı, üzerinde çalışan uygulamaları bulunduğu işletim sisteminden bağımsız olmasını sağlamaktır.

1990’ların sonlarında açık sistemler diye tabir edilen x86 sistemlerinin sanallaştırma dünyasına uyarlanma sonucunda, sanallaştırma kısa zamanda bilgi teknolojilerinin merkezine oturmuştur. 2000’li yıllar geldiğinde Sun, Microsoft, VMware vb. firmalar müşterilerine ürünlerini sunmaya başlayarak bugün kullanmış olduğumuz sanallaştırma yazılımlarının ilk halleri ortaya çıkmıştır.

Sanallaştırma Sonrasındaki Yapı

– Sanal makine yazılımı en temel haliyle, HDD üstünde bir dosyadır

– Sanal makine yöntemi ile işletim sistemi belirli bir fiziksel donanımdan bağımsız hale gelerek herhangi bir donanıma taşınabilir

– Sanal uygulama yöntemi ile uygulamalar artık içerisinde çalışacağı belirli bir işletim sistemine bağımlı olmaktan çıkar ve başka bilgisayarlara taşınabilir hale gelir.

– Sanal makine belirli bir yerdeki fiziksel depolama ve network kaynaklarına bağımlı olmaktan çıkarak sanal depolama ve network kaynaklarını kullanabilir.

Sanallaştırma günümüzde iki farklı biçimde sunulmaktadır. Esasında bunlar sanallaştırma için kullanılan temel yazılım olan hypervisor ın çeşidine göre çoklanmıştır. Bkz => http://en.wikipedia.org/wiki/Hypervisor

Host Tabanlı Sanallaştırma

Host tabanlı sanallaştırma geleneksel bilgisayar yapısından biraz farklılık göstermektedir. Fiziksel donanım aygıtları üzerine Windows, Linux vb. bir işletim sistemi kurulmaktadır. Bu işletim sistemi üzerine de sanallaştırma platformu kurulmaktadır.

sanallastirilmis_ortam

sanallastirma_infrastructure

Donanım Tabanlı Sanallaştırma

Donanım tabanlı sanallaştırma platformunda host tabanlı sanallaştırmadan farklı olarak donanım aygıtları üzerine kurulan bir işletim sistemi bulunmaz.

Sanallaştırma direkt olarak bilgisayar donanımı üzerine kurulan sanallaştırma platformu ile sağlanır, bu nedenle bare-metal olarak da bilinir.

Bu sanallaştırma platformu yine de yazılım katmanına ihtiyaç duymaktadır. Ancak bu kodlar tamamen yazılımsal olan çözümlerinkinden çok daha kısa ve basittir. Sanallaştırma donanım tarafından da desteklendiğinden çok daha güçlüdür. (Simple is better)

Fiziksel donanım ile bu platform arasında başka bir aracı yer almadığından daha güvenli ve performanslıdır. Aşağıdaki resimde arada katmanın bulunmadığı görülebilir.

sanallastirma

Kullanım Alanları:

Test ve Geliştirme

Örneğin bir teknoloji şirktetin geliştirilen birçok proje bulunur ve bunun testi için gereken makinenin sistem kaynakları canlı kullanımdaki kadar yüksek değildir(performans testleri hariç) Bunun için yeni bir server ve işletim sistemine gerek duyulsa maliyet yükselecektir . Bunun önüne güçlü bir makinede birden fazla sunucu ve işletim sisteminin sanallaştırılmasıyle çözülebilir. Farklı işletim sistemlerinde uygulamalar test edilebilmektedir. Birden fazla sanal makine çeşitli varyasyonlar için kullanılabilmektedir. İhtiyaç olduğunda yeni sunucular hızlı bir şekilde oluşturulabilmektedir.

Sunucu Konsolidasyonu

Farklı sunucular üzerindeki sistem kaynaklarını düşük seviyede kullanan uygulamalar, tek bir sunucu üzerinde çalıştırılarak fiziksel donanım, enerji, alan vb. masraflardan tasarruf edilmektedir. Windows, Linux vb. işletim sistemleri aynı sunucu üzerinde eş zamanlı olarak çalıştırarak kaynakların verimli kullanılmasını sağlanmakta, operasyonel etkinliği arttırmaktadır.

Teknik Eğitim

Günümüzde birçok gelişmiş sınıfta her öğrenci için bir bilgisayar bulunmaktadır. Sanallaştırma ile kurumlar her bir sınıf için gerekli olan fiziksel bilgisayar sayısını düşürebilmektedir. Eğitim bilgisayarlarının kurulumunu kolaylaştırarak, bir sonraki sınıf için bilgisayarları hızlıca yapılandırabilmektedir.

İş Sürekliliği

Sanallaştırma High Availability (HA), Disaster Recovery (DR) vb. özellikleri ile felaket durumlarında bilgi teknolojileri hizmetlerinin sürekliliğini sağlamaktadır.

Ücretsiz Sanallaştırma Yazılımları

Oracle Virtual Box

Açık kaynak kodludur. Windows, Linux ve Macintosh ve OpenSolaris hostaları üzerinde çalışmaktadır. Windows, Linux, Solaris, IBM OS/2 gibi işletim sistemlerini desteklemektedir. Snapshot çalışma özelliği bulunmaktadır.

VMware Player

Host tabanlı olan yazılım, Windows, Linux, Nowel, Sun Solaris vb. işletim sistemlerini desteklemektedir. Hazır sanal çözüm paketlerini internetten indirerek kullanabilmektedir. Acronis programıyla oluşturulmuş tib uzantılı dosyaları, Symantec Backup programının sv2i uzantılı dosyalarını, Virtual PC ve Virtual Server tarafından oluşturulan dosyalara da destek verebilmektedir.

Citrix XenServer

Direk donanım üzerine kurulan (donanım tabanlı hypervisor) open source, Xen hypervisor tabanlı ücretsiz sanallaştırma platformudur. Çoklu sunucu yönetim konsolu, sanal makine şablonları, snapshot, kaynak havuzları, live migration gibi özellikleri bulunmaktadır.

VMware ESXi Server

Donanım tabanlı bu yazılım, ticari bir ürün olan VMware ESX’in gelişmiş özelliklerinden yoksun paketidir.

Giriş Seviyesindeki Ticari Yazılımlar

VMware Workstation

Vmware Fusion

Paralles Desktop

Cloud Computing

Bulut bilgi işlem, internet üzerinden gerçek zamanlı şekilde ürünlerin, servislerin, çözümlerin taşınmasını ve talep edildiği kadar (utility computing)tüketilmesini sağlamaktır. Sunucu konsolidasyonu ile merkezileşme ve kaynakların etkin bir şekilde paylaşılması dünyada yeni fikirleri ortaya çıkarmış ve “Bulut Bilişim” denen yeni bir yaklaşım/teknoloji doğmuştur. Bu yaklaşım ile tüketici dilediği kadar kaynağı dinamik olarak kullanmakta ve kullandığı kaynak kadar ödeme yapmaktadır.

Bulut bilgi işlem, ihtiyaç duyulan verilerin ve hesaplamaların tüketici bilgisayarı yerine uzaktaki birçok bilgisayarda tutulması ve hesaplanması mantığına dayanmaktadır. Hesaplanan veriler daha sonrasında internet üzerinden tüketicinin bilgisayarına yönlendirilmektedir. Tüketici verilere dünyanın herhangi bir yerinden ve herhangi bir donanımla erişilebilmektedir.

Geleneksel iş uygulamalarının karışık ve pahalı olması Cloud Computing teknolojinin hızla ilerlemesinin ve yaygınlaşmasının önünü açmıştır. Geleneksel yazılımların yanı sıra bu yazılımlar için gereken veri merkezi, kesintisiz enerji, soğutma, sunucular, veri depolama çözümleri gibi ek yükler de işletmelerde önemli iş gücü ve finansal kaynak gerektirmektedir. Tüketici bulut üzerinde herhangi bir yazılımı kullanmak istediğinde ise sisteme bağlanıp parametrik ayarlamaları kendisine göre yaparak hemen sistemi kullanmaya başlayabilmektedir. Bulut Bilgi İşlem’in en büyük gücü hızlı, pratik ve kullandığın kadar öde sistemine sahip oluşunda yatmaktadır. En önemli özelliği ise fiyat/performans oranının yüksek maliyetlerinin düşürülebilir olmasıdır. Tüketiciler yazılım lisansları, yazılımı uygulayacak projeciler ve geliştiriciler ve yazılımı yönetecek BT personelleri azaldığından fazla para ödemek zorunda kalmadıklarından maliyetler düşmektedir.

Çalıştığım teknoloji firmasındaki sanallaştırmadan biraz bahsetmek gerekirse. Oracle çözüm ortağı olarak faaliyet gösteren yazılım geliştirme firması, bir adet güçlü bir sunucu bulundurmaktadır. Oracle Fusion Middleware ürünleri (UCM, BPM, vs)üzerine yazılımlar konumlandırmaktayız. Bir projeye başladığımızda bir çok sunucu ve uygulama ihtiyacı doğmaktadır. Örneğin bir Doküman Yönetim Sistemi projesinde, portal sunucusu, BPM (Business Process Management) sunucusu, geliştirilen uygulamanın koşacağı managedServer, Active Directory, Oracle Database…

Her müşteri için ayrı makineler, ayrı işletim sistemleri, ayrı kaynak kullanımının önüne geçebilmek için sunucuları sanallaştırdık. Oracle Ortakatman ürünleri için bir sanal sunucu, veritabanı için bir sanal sunucu, AD için bir sanal sunucu konumlandırarak. Yedeklemesi kapatması ve yeni müşteri projeler için hızlıca yenisini temin ederek yönetilebilir hale getirebiliyoruz.