Skip to content

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:

DSN As String
ODBC kaynağının adı
user As String
bağlantının oluşturulacağı kimlik
passwd As String
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>
...
</objects>

<objects>, bir Spring yapılandırma dosyasının kök etiketidir. Bu etiket, örneklenecek singleton nesnelerin tanımını içerir.

    <description>Gestion d'une table d'articles</description>

<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:

        Public Sub New(ByVal DSN As String, ByVal user As String, ByVal passwd As String)

[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:

Image

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:

Image

  • Spring'i kullanan sınıflar, genellikle aşağıdakiler de dahil olmak üzere belirli ad alanlarını içe aktarmalıdır:
Imports Spring.Objects.Factory.Xml

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.