2. Spring ile bir uygulamayı yapılandırma
Klasik bir 3-katmanlı uygulamayı ele alalım:
![]() |
DAO katmanına erişimin bir [IArticlesDao] arayüzü tarafından kontrol edildiğini varsayalım:
....
Namespace istia.st.articles.dao
Public Interface IArticlesDao
' tüm ürünlerin listesi
Function getAllArticles() As IList
' bir ürün ekler
Function ajouteArticle(ByVal unArticle As Article) As Integer
' bir ürünü siler
Function supprimeArticle(ByVal idArticle As Integer) As Integer
' bir ürünü düzenler
Function modifieArticle(ByVal unArticle As Article) As Integer
' bir makaleyi ara
Function getArticleById(ByVal idArticle As Integer) As Article
' tüm ürünleri sil
Sub clearAllArticles()
' bir işleme ürün ekler
Sub doInsertionsInTransaction(ByVal articles As Article())
' bir ürünün stokunu değiştirir
Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer
End Interface
End Namespace
Veri erişim katmanında veya DAO katmanında (Veri Erişim Nesnesi), bir SGBD ile çalışmak yaygın bir durumdur. Buna bir ODBC sürücüsü aracılığıyla erişildiğini varsayalım. Bu ODBC kaynağına erişen bir sınıfın iskeleti şu şekilde olabilir:
NameSpace istia.st.articles.dao
Imports System.Data.Odbc
...
Public Class ArticlesDaoPlainODBC
Implements istia.st.articles.dao.IArticlesDao
' özel alanlar
Private connexion As OdbcConnection = Nothing
Private DSN As String
Public Sub New(ByVal DSN As String, ByVal user As String, ByVal passwd As String)
' kaynağın adını alır ODBC
Me.DSN = DSN
' bağlantı dizesi oluşturulur
Dim connectString As String = String.Format("DSN={0};UID={1};PWD={2}", DSN, user, passwd)
' bağlantıyı başlatır
connexion = New OdbcConnection(connectString)
End Sub
....
End Class
End NameSpace
ODBC kaynağında bir işlem gerçekleştirmek için, her yöntemin, veritabanı ile uygulama arasındaki veri alışverişinin gerçekleşeceği veritabanı bağlantısını temsil eden bir [OdbcConnection] nesnesine ihtiyacı vardır. Bu nesneyi oluşturmak için üç bilgiye ihtiyaç vardır:
ODBC kaynağının adı | |
bağlantının oluşturulacağı kimlik | |
bu kimliğe ait şifre |
[ArticlesDaoPlainODBC] sınıfımız, sınıfın bir üyesini örneklendiren harici aracı aracılığıyla bu bilgileri alır. Bu aracının, [ArticlesDaoPlainODBC] sınıfını örneklendirmek için gerekli olan üç bilgiyi nasıl elde ettiği merak edilebilir. Bir örnek verelim. [Dao] katmanının bir test sınıfı yazmak istediğimizi varsayalım. Şu mimariye sahip olurduk:
![]() |
Bir Nunit test sınıfı olan [http://www.nunit.org/]'in iskeleti şu şekilde olabilir:
Imports System
Imports System.Collections
Imports NUnit.Framework
Imports istia.st.articles.dao
Imports ArticlesDaoSqlmap = istia.st.articles.dao.ArticlesDaoSqlMap
Imports Article = istia.st.articles.domain.Article
Imports System.Threading
<TestFixture()> _
Public Class NunitTestArticlesDaoPlainOdbc
' test edilecek nesne
Private articlesDao As IArticlesDao
<SetUp()> _
Public Sub init()
' test edilecek nesnenin bir örneği oluşturulur
articlesDao = New ArticlesDaoPlainODBC("odbc-firebird-articles", "SYSDBA", "masterkey")
End Sub
<Test()> _
Public Sub testGetAllArticles()
' görsel kontrol
listArticles()
End Sub
' ekran çıktısı
Private Sub listArticles()
Dim articles As IList = articlesDao.getAllArticles
For i As Integer = 0 To articles.Count - 1
Console.WriteLine(CType(articles(i), Article).ToString)
Next
End Sub
End Class
Nunit test ortamı, Java platformu için mevcut olan JUnit ortamının .NET platformuna uyarlanmış halidir. Yukarıdaki sınıfta, <SetUp()> özniteliğine sahip yöntem her test yönteminden önce yürütülür. <TearDown()> özniteliğine sahip yöntem ise her testten sonra yürütülür. Yukarıdaki örnekte böyle bir yöntem bulunmamaktadır. Burada, <SetUp()> özniteliğine sahip [init] yönteminin, bu nesnenin oluşturucusunun ihtiyaç duyduğu üç bilgiyi "sabit" olarak aktararak bir [ArticlesDaoPlainODBC] nesnesini oluşturduğunu görüyoruz.
Test sınıfımız, "sabit" olarak kodlanmış bilgilerden birinde meydana gelebilecek bir değişikliğin etkisine maruz kalmaktadır. Bu bilgiler, değiştiğinde gereksiz yeniden derlemeleri önlemek amacıyla bir yapılandırma dosyasına kaydedilse daha iyi olurdu. Bir uygulamayı yapılandırmak için genel olarak kullanılan çözüm, zaman içinde değişebilecek tüm bilgilerin yer aldığı bir dosyanın kullanılmasıdır. Çok çeşitli yapılandırma dosyaları mevcuttur. Güncel eğilim, XML dosyalarının kullanılması yönündedir. Spring de bu seçeneği benimsemiştir. Bir [ArticlesDaoPlainODBC] nesnesini yapılandıran dosya şu şekilde olabilir:
<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">
<objects>
<!-- IArticlesDao arayüzünün uygulama sınıfı -->
<description>Gestion d'une table d'articles</description>
<object id="articlesdao" type="istia.st.articles.dao.ArticlesDaoPlainODBC, articlesdao">
<constructor-arg index="0">
<value>odbc-firebird-articles</value>
</constructor-arg>
<constructor-arg index="1">
<value>SYSDBA</value>
</constructor-arg>
<constructor-arg index="2">
<value>masterkey</value>
</constructor-arg>
</object>
</objects>
Spring yapılandırma dosyası, örneklenecek nesneleri tanımlar. Genellikle, bunların ne zaman örnekleneceği belirtilmez. Dolayısıyla, örneklenme zamanı bu dosyayı kullanan kod tarafından belirlenir. Spring yapılandırma dosyasında tanımlanan nesneler, iki farklı şekilde örneklenebilir ve başlatılabilir:
- yukarıda olduğu gibi, nesnenin oluşturucusuna aktarılacak parametreleri belirterek
- nesnenin özelliklerine (Property) değerler atayarak. Bu durumda, nesnenin Spring'in örneklendirme için kullanacağı bir varsayılan yapıcıya sahip olması gerekir.
Bir uygulamada hizmet sunma görevini üstlenen nesneler genellikle tek bir kopya olarak oluşturulur. Bunlara singleton denir. Dolayısıyla, bu belgenin başında sunulan çok katmanlı uygulama örneğimizde, ürün veritabanına erişim, [ArticlesDaoPlainODBC] sınıfının tek bir kopyası tarafından sağlanacaktır. Bir web uygulamasında, bu hizmet nesneleri aynı anda birden fazla müşteriye hizmet eder. Her müşteri için ayrı bir hizmet nesnesi oluşturulmaz.
Yukarıdaki Spring yapılandırma dosyası, [ArticlesDaoPlainODBC] türünde tek bir hizmet nesnesinin [istia.st.articles.dao] adlı bir pakette oluşturulmasını sağlar. Bu nesnenin oluşturucusu için gerekli olan üç bilgi, <object>...</object> etiketleri içinde tanımlanır. Oluşturulacak tekil nesne sayısı kadar <object> etiketi bulunur.
Yapılandırmayı ayrıntılı olarak inceleyelim:
<objects>, bir Spring yapılandırma dosyasının kök etiketidir. Bu etiket, örneklenecek singleton nesnelerin tanımını içerir.
<description> etiketi isteğe bağlıdır. Örneğin, yapılandırma dosyasının rolünü açıklamak için kullanılabilir.
<object id="articlesdao" type="istia.st.articles.dao.ArticlesDaoPlainODBC, articlesdao">
...
</object>
<object> etiketi, örneklenecek bir nesneyi tanımlamak için kullanılır. Burada iki özniteliği vardır:
- name: nesnenin tanımlayıcısı. Dış kod, bu ad aracılığıyla nesneye başvurur.
- class: "sınıf adı, derleme adı" biçimindedir. İlk bilgi, örneklenecek sınıfın tam adıdır. İkincisi ise, bu sınıfı içeren DLL dosyasının adıdır. Örneğimizde, sınıf [articlesdao.dll] adlı bir dosyada bulunmaktadır.
<object> etiketinin içeriği, nesnenin nasıl oluşturulacağını tanımlamak için kullanılır:
<object id="articlesdao" type="istia.st.articles.dao.ArticlesDaoPlainODBC, articlesdao">
<constructor-arg index="0">
<value>odbc-firebird-articles</value>
</constructor-arg>
<constructor-arg index="1">
<value>SYSDBA</value>
</constructor-arg>
<constructor-arg index="2">
<value>masterkey</value>
</constructor-arg>
</object>
[ArticlesDaoPlainODBC] sınıfının üretici imzasını hatırlayalım:
[articlesdao] Spring nesnesi, yukarıdaki oluşturucu tarafından yapılandırma dosyasındaki üç bilgi ile örneklenecektir: [odbc-firebird-articles, SYSDBA, masterkey].
Spring dosyasında tanımlanan nesnelerin oluşturulması ne zaman gerçekleşecek? Her uygulamada, ilk olarak çalıştırılacağı kesin olan bir yöntem bulunur. Genellikle singleton nesnelerin oluşturulması bu yöntem içinde talep edilir. Uygulamanın başlatılması, eğer varsa, aynı uygulamanın main yöntemine devredilebilir. ASP.NET uygulaması için bu, [global.asax] dosyasındaki [Application_Start] yöntemi olabilir. [Nunit] test sınıfımız için, uygulamanın başlatılması <Setup()> özniteliğiyle ilişkili yöntemde gerçekleşir.
Yukarıdaki yapılandırma dosyasını [Nunit] sınıfımızda nasıl kullanabiliriz? İşte bir örnek:
Imports System
Imports System.Collections
Imports NUnit.Framework
Imports istia.st.articles.dao
Imports ArticlesDaoSqlmap = istia.st.articles.dao.ArticlesDaoSqlMap
Imports Article = istia.st.articles.domain.Article
Imports System.Threading
Imports Spring.Objects.Factory.Xml
Imports System.IO
<TestFixture()> _
Public Class NunitSpringTestArticlesDaoPlainOdbc
' test edilecek nesne
Private articlesDao As IArticlesDao
<SetUp()> _
Public Sub init()
' Spring nesne oluşturucusunun bir örneği alınır
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-plainodbc.xml", FileMode.Open))
' articles DAO nesnesinin örneklenmesi istenir
articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
End Sub
<Test()> _
Public Sub testGetAllArticles()
' görsel kontrol
listArticles()
End Sub
' ekran çıktısı
Private Sub listArticles()
Dim articles As IList = articlesDao.getAllArticles
For i As Integer = 0 To articles.Count - 1
Console.WriteLine(CType(articles(i), Article).ToString)
Next
End Sub
End Class
Açıklamalar:
- Spring yapılandırma dosyasındaki nesneleri oluşturmak için [XmlObjectFactory] türünde bir nesne kullanılır. Bu, "Factory" türünde bir nesnedir (c.a.d). Bu nesne, başka nesneler oluşturmak için kullanılır (Factory = fabrika). Spring, kullanılan yapılandırma dosyasına göre çeşitli "Factory" türlerine sahiptir. Burada, yapılandırma dosyası XML olduğundan, [XmlObjectFactory] türü kullanılır.
- Oldukça mantıklı bir şekilde, [XmlObjectFactory] türündeki bir nesne, XML yapılandırma dosyasının adına ihtiyaç duyar; burada bu isim [spring-config-plainodbc.xml]'tir. Tam olarak, [XmlObjectFactory] türü, adı belirtilen XML dosyasından oluşturulan bir okuma akışıyla örneklenir.
- [XmlObjectFactory] türündeki nesne oluşturulduktan sonra, [XmlObjectFactory] aracılığıyla yapılandırma dosyasından bir nesne elde edilir.getObject("kimlik"), burada "kimlik", yapılandırma dosyasındaki nesnelerden birinin [id] özniteliğidir.
- İstenen nesne henüz örneklenmemişse, Spring onu yapılandırma dosyasındaki bilgileri kullanarak örneklendirir ve çağıran programa bir referans döndürür. Nesne daha önce örneklenmişse, Spring sadece mevcut nesnenin referansını döndürür. Bu, singleton ilkesidir.
- [Nunit] test sınıfının, veri erişim sınıfının adını bilmediğine dikkat edilmelidir. Bu ad, yapılandırma dosyasında yer alır. Test sınıfı, yalnızca [IArticlesDao] arayüzünü uygulayan bir nesne talep eder:
' test edilecek nesne
Private articlesDao As IArticlesDao
<SetUp()> _
Public Sub init()
...
articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
End Sub
Spring'in en önemli avantajı da budur. Uygulama sınıfını değiştirirsek, test sınıfımızı değiştirmemiz gerekmez. Sadece Spring yapılandırma dosyasını değiştirmemiz yeterlidir. Test sınıfı ise bir sınıfla değil, bir arayüzle çalışır.
Bu sunumu birkaç pratik noktayla bitirelim.
"Spring şunu örneklendirecek..." dediğimizde, tam olarak ne demek istiyoruz? .NET platformu için Spring, üç dosyada yer alır:

Visual Studio ile oluşturulmuş ve Spring kullanması gereken bir .NET projesi için şu şekilde ilerleyeceğiz:
- Yukarıdaki üç dosya, projenin [bin] klasörüne yerleştirilecektir
- [Spring.Core.dll], projenin referansları arasında yer almalıdır:

- Spring'i kullanan sınıflar, genellikle aşağıdakiler de dahil olmak üzere belirli ad alanlarını içe aktarmalıdır:
Bir başka pratik nokta: Spring yapılandırma dosyası nereye yerleştirilir? Bunun için birkaç olası yer vardır. Bunlardan biri, projenin [bin] klasörüdür. İncelenen örnekteki [spring-config-plainodbc.xml] dosyası buraya yerleştirilmiştir.

