Skip to content

7. Bir çözüm

7.1. Visual Studio projesi

Açıklamalar:

  • Spring için gerekli dosyalar [bin] klasörüne yerleştirilmiştir: Spring.Core.dll, log4net.dll, Spring.Core.xml
  • Spring yapılandırma dosyaları [spring-config-3tier-*.xml] de [bin] klasörüne yerleştirilmiştir
  • [istia] kök dizininde ise uygulamanın çeşitli sınıfları bulunmaktadır

Proje, DLL ve [spring3tier.dll] dosyalarını [bin] klasöründe oluşturacak şekilde yapılandırılmıştır:

Image

7.2. [istia.st.spring3tier.dao] paketi

IDao arayüzü:

Namespace istia.st.spring3tier.dao
    Public Interface IDao
         ' katmanda bir şey yapmak [dao]
        Function doSomethingInDaoLayer(ByVal a As Integer, ByVal b As Integer) As Integer
    End Interface
End Namespace

Birinci sınıf bir uygulama:

Namespace istia.st.spring3tier.dao
    Public Class DaoImpl1
        Implements istia.st.spring3tier.dao.IDao

         ' katmanda bir şey yapmak [dao]
        Public Function doSomethingInDaoLayer(ByVal a As Integer, ByVal b As Integer) As Integer Implements IDao.doSomethingInDaoLayer

            Return a + b
        End Function
    End Class

End Namespace
  • Sınıfın özel alanı yoktur
  • [doSomethingInDaoLayer] yöntemi, istenildiği gibi parametrelerinin toplamını verir.

İkinci bir uygulama sınıfı:

Namespace istia.st.spring3tier.dao
    Public Class DaoImpl2
        Implements istia.st.spring3tier.dao.IDao

         ' katmanda bir şey yapmak [dao]
        Public Function doSomethingInDaoLayer(ByVal a As Integer, ByVal b As Integer) As Integer Implements IDao.doSomethingInDaoLayer

            Return a - b
        End Function
    End Class

End Namespace
  • Sınıfın özel alanı yoktur
  • [doSomethingInDaoLayer] yöntemi, istenildiği gibi parametrelerinin farkını döndürür.

7.3. [istia.st.spring3tier.domain] paketi

IDomain arayüzü:

Namespace istia.st.spring3tier.domain
    Public Interface IDomain
         ' [domain] katmanında bir şey yapmak
        Function doSomethingInDomainLayer(ByVal a As Integer, ByVal b As Integer) As Integer
    End Interface
End Namespace

Birinci sınıf bir uygulama örneği IDomainImpl1:

Imports istia.st.spring3tier.dao

Namespace istia.st.spring3tier.domain
    Public Class DomainImpl1
        Implements istia.st.spring3tier.domain.IDomain

         ' özel alanlar
        Private _dao As IDao

         ' ilişkili özellik
        Public WriteOnly Property dao() As IDao
            Set(ByVal Value As IDao)
                _dao = Value
            End Set
        End Property

         ' varsayılan oluşturucu
        Public Sub New()
        End Sub

         ' [domain] katmanında bir şey yapmak
        Public Function doSomethingInDomainLayer(ByVal a As Integer, ByVal b As Integer) As Integer Implements IDomain.doSomethingInDomainLayer
            a += 1
            b += 1
            Return _dao.doSomethingInDaoLayer(a, b)
        End Function
    End Class

End Namespace
  • Sınıfın, [IDao] türündeki tekil nesneye bir referans olan özel bir alanı vardır; bu alan, [Dao] katmanına erişim sağlar. Bu alan, nesnenin oluşturulduğu sırada Spring tarafından (bağımlılık enjeksiyonu yoluyla) başlatılacaktır.
  • [doSomethingInDomainLayer] yöntemi, parametrelerini artırır ve ardından bunları [dao] singletonunun [doSomethingInDaoLayer] yöntemine aktarır.

İkinci bir uygulama sınıfı IDomainImpl2:

Imports istia.st.spring3tier.dao

Namespace istia.st.spring3tier.domain
    Public Class DomainImpl2
        Implements istia.st.spring3tier.domain.IDomain

         ' özel alanlar
        Private _dao As IDao

         ' ilişkili özellik
        Public WriteOnly Property dao() As IDao
            Set(ByVal Value As IDao)
                _dao = Value
            End Set
        End Property

         ' varsayılan oluşturucu
        Public Sub New()
        End Sub

         ' [domain] katmanında bir şey yapmak
        Public Function doSomethingInDomainLayer(ByVal a As Integer, ByVal b As Integer) As Integer Implements IDomain.doSomethingInDomainLayer
            a -= 1
            b -= 1
            Return _dao.doSomethingInDaoLayer(a, b)
        End Function
    End Class

End Namespace
  • Sınıfın, [IDao] türündeki tekil nesneye bir referans olan özel bir alanı vardır; bu alan, [Dao] katmanına erişim sağlar. Bu alan, nesnenin oluşturulduğu sırada Spring tarafından (bağımlılık enjeksiyonu yoluyla) başlatılacaktır.
  • [doSomethingInDomainLayer] yöntemi, parametrelerini bir azaltır ve ardından bunları [dao] singletonunun [doSomethingInDaoLayer] yöntemine aktarır

7.4. [istia.st.spring3tier.control] paketi

IControl arayüzü:

Namespace istia.st.spring3tier.control
    Public Interface IControl
         ' [control] katmanında bir şey yapmak
        Function doSomethingInControlLayer(ByVal a As Integer, ByVal b As Integer) As Integer
    End Interface
End Namespace

Birinci sınıf bir uygulama örneği ControlImpl1:

Imports istia.st.spring3tier.domain

Namespace istia.st.spring3tier.control
    Public Class ControlImpl1
        Implements istia.st.spring3tier.control.IControl

         ' özel alanlar
        Private _domain As IDomain

         ' ilişkili özellik
        Public WriteOnly Property domain() As IDomain
            Set(ByVal Value As IDomain)
                _domain = Value
            End Set
        End Property

         ' varsayılan oluşturucu
        Public Sub New()
        End Sub

         ' [control] katmanında bir şey yapmak
        Public Function doSomethingInControlLayer(ByVal a As Integer, ByVal b As Integer) As Integer Implements IControl.doSomethingInControlLayer
            a += 1
            b += 1
            Return _domain.doSomethingInDomainLayer(a, b)
        End Function
    End Class

End Namespace
  • Sınıfın, [IDomain] türündeki tekil nesneye bir referans olan özel bir alanı vardır; bu alan, [Domain] katmanına erişim sağlar. Bu alan, nesnenin oluşturulduğu sırada Spring tarafından (bağımlılık enjeksiyonu yoluyla) başlatılacaktır.
  • [doSomethingInControlLayer] yöntemi, parametrelerini artırır ve ardından bunları [domain] singletonunun [doSomethingInDomainLayer] yöntemine aktarır.

İkinci bir uygulama sınıfı IControlImpl2:

Imports istia.st.spring3tier.domain

Namespace istia.st.spring3tier.control
    Public Class ControlImpl2
        Implements istia.st.spring3tier.control.IControl

         ' özel alanlar
        Private _domain As IDomain

         ' ilişkili özellik
        Public WriteOnly Property domain() As IDomain
            Set(ByVal Value As IDomain)
                _domain = Value
            End Set
        End Property

         ' varsayılan oluşturucu
        Public Sub New()
        End Sub

         ' [control] katmanında bir şey yapmak
        Public Function doSomethingInControlLayer(ByVal a As Integer, ByVal b As Integer) As Integer Implements IControl.doSomethingInControlLayer
            a -= 1
            b -= 1
            Return _domain.doSomethingInDomainLayer(a, b)
        End Function
    End Class

End Namespace
  • Sınıfın, [IDomain] türündeki tekil nesneye bir referans olan özel bir alanı vardır; bu alan, [Domain] katmanına erişim sağlar. Bu alan, nesnenin oluşturulduğu sırada Spring tarafından (bağımlılık enjeksiyonu yoluyla) başlatılacaktır.
  • [doSomethingInControlLayer] yöntemi, parametrelerini azaltır ve ardından bunları [domain] singletonunun [doSomethingInDomainLayer] yöntemine aktarır.

7.5. [Spring] yapılandırma dosyaları

[spring-config-3tier-1.xml] dosyası, aşağıdaki uygulamaların 1. sürümlerini kullanır:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">
<objects>
     <!-- DAO sınıfı -->
    <object id="dao" type="istia.st.spring3tier.dao.DaoImpl1, spring3tier"></object>
     <!-- domain sınıfı -->
    <object id="domain" type="istia.st.spring3tier.domain.DomainImpl1, spring3tier">
        <property name="dao">
            <ref object="dao" />
        </property>
    </object>
     <!-- kontrol sınıfı -->
    <object id="control" type="istia.st.spring3tier.control.ControlImpl1, spring3tier">
        <property name="domain">
            <ref object="domain" />
        </property>
    </object>
</objects>

[spring-config-3tier-2.xml] dosyası, aşağıdaki uygulamaların 2. sürümlerini kullanır:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">
<objects>
     <!-- DAO sınıfı -->
    <object id="dao" type="istia.st.spring3tier.dao.DaoImpl2, spring3tier"></object>
     <!-- domain sınıfı -->
    <object id="domain" type="istia.st.spring3tier.domain.DomainImpl2, spring3tier">
        <property name="dao">
            <ref object="dao" />
        </property>
    </object>
     <!-- kontrol sınıfı -->
    <object id="control" type="istia.st.spring3tier.control.ControlImpl2, spring3tier">
        <property name="domain">
            <ref object="domain" />
        </property>
    </object>
</objects>

7.6. [istia.st.spring3tier.tests] test paketi

Bir Nunit testi [NunitTestSpring3tier.vb]:

Imports System
Imports Spring.Objects.Factory.Xml
Imports System.IO
Imports NUnit.Framework
Imports istia.st.spring3tier.control
Imports istia.st.spring3tier.domain

Namespace istia.st.springioc.tests

    <TestFixture()> _
    Public Class NunitTestSpring3tier
         ' singleton fabrikaları
        Private factory1 As XmlObjectFactory
        Private factory2 As XmlObjectFactory

        <SetUp()> _
        Public Sub init()
             ' singleton fabrikaları oluşturulur
            factory1 = New XmlObjectFactory(New FileStream("spring-config-3tier-1.xml", FileMode.Open))
            factory2 = New XmlObjectFactory(New FileStream("spring-config-3tier-2.xml", FileMode.Open))
        End Sub

        <TearDown()> _
        Public Sub destroy()
             ' singleton'ları yok ediyoruz
            factory1.Dispose()
            factory2.Dispose()
             ' singleton fabrikalarını serbest bırakma
            factory1 = Nothing
            factory2 = Nothing
        End Sub

        <Test()> _
        Public Sub test()
             'arayüzün bir uygulamasını alıyoruz IControl
            Dim control1 As IControl = CType(factory1.GetObject("control"), IControl)
             ' sınıfı kullanıyoruz
            Dim a1 As Integer = 10, b1 As Integer = 20
            Dim res1 As Integer = control1.doSomethingInControlLayer(a1, b1)
            Assert.AreEqual(34, res1)
             ' IControl arayüzünün başka bir uygulamasını alıyoruz
            Dim control2 As IControl = CType(factory2.GetObject("control"), IControl)
             ' sınıfı kullanıyoruz
            Dim a2 As Integer = 10, b2 As Integer = 20
            Dim res2 As Integer = control2.doSomethingInControlLayer(a2, b2)
            Assert.AreEqual(-10, res2)
        End Sub

    End Class
End Namespace

Bu testin gerçekleştirilmesi sonucunda aşağıdaki sonuçlar elde edilir:

Image

Bu belgenin renkli sürümüne sahip okuyucular, sonuçların "yeşil" olduğunu ve bunun testin başarılı olduğunu gösterdiğini göreceklerdir.

7.7. Başka bir Spring yapılandırma dosyası türü

Bir VB.net uygulaması, [App.config] adlı bir dosya kullanılarak yapılandırılabilir. Bu dosya, Visual Studio projesinin kök dizinine yerleştirilir:

Image

Spring bu yapılandırma dosyasından yararlanabilir. [Spring.net] belgelerindeki örneklerden esinlenerek hazırlanan aşağıdaki [App.config] dosyasını ele alalım:

<?xml version="1.0" encoding="iso-8859-1" ?>
<configuration>
    <configSections>
        <sectionGroup name="spring">
            <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
            <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
        </sectionGroup>
    </configSections>
    <spring>
        <context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
            <resource uri="config://spring/objects" />
        </context>
        <objects>
             <!-- ilk yapılandırma -->
             <!-- dao sınıfı -->
            <object id="dao1" type="istia.st.spring3tier.dao.DaoImpl1, spring3tier"></object>
             <!-- domain sınıfı -->
            <object id="domain1" type="istia.st.spring3tier.domain.DomainImpl1, spring3tier">
                <property name="dao">
                    <ref object="dao1" />
                </property>
            </object>
             <!-- control sınıfı -->
            <object id="control1" type="istia.st.spring3tier.control.ControlImpl1, spring3tier">
                <property name="domain">
                    <ref object="domain1" />
                </property>
            </object>
             <!-- ikinci bir yapılandırma -->
             <!-- DAO sınıfı -->
            <object id="dao2" type="istia.st.spring3tier.dao.DaoImpl2, spring3tier"></object>
             <!-- domain sınıfı -->
            <object id="domain2" type="istia.st.spring3tier.domain.DomainImpl2, spring3tier">
                <property name="dao">
                    <ref object="dao2" />
                </property>
            </object>
             <!-- kontrol sınıfı -->
            <object id="control2" type="istia.st.spring3tier.control.ControlImpl2, spring3tier">
                <property name="domain">
                    <ref object="domain2" />
                </property>
            </object>
        </objects>
    </spring>
</configuration>

Not: Aşağıdaki bilgiler kesin değildir. Yukarıdaki yapılandırma dosyasındaki tüm öğelerin anlamını doğru bir şekilde anladığımdan emin değilim.


XML dosyasının [App.config] sözdizimi, şu sözdizimine uymasını gerektirir:

<configuration>
....
</configuration>

[App.config] dosyasının farklı bölümlerinin yönetimi harici programlara devredilebilir. [ConfigSections] bölümünde de bu şekilde yapılmıştır:

    <configSections>
        <sectionGroup name="spring">
            <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
            <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
        </sectionGroup>
    </configSections>

Yukarıdaki kod, [spring/context] adlı bölümün, [Spring.Context.Support.ContextHandler] sınıfı tarafından yönetilmesi gerektiğini belirtir; bu sınıf[Spring.Core.dll] montajında bulunur ve [spring/objects] adlı bölümün, yine [Spring.Core.dll] montajında bulunan [Spring.Context.Support.DefaultSectionHandler] sınıfı tarafından yönetilmesi gerektiğini ifade eder.

[spring/context] bölümü şu şekildedir:

    <spring>
        <context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
            <resource uri="config://spring/objects" />
        </context>
...
    </spring>

Burada, yapılandırma dosyasının [spring/objects] bölümü, [Spring.Core.dll] derlemesinde bulunan [Spring.Context.Support.XmlApplicationHandler] sınıfı tarafından yönetilmesi gerektiği belirtiliyor gibi görünüyor. Bu sınıf, konumu [ config://spring/objects], c.a.d olan XML kaynağını kullanmalıdır. mevcut yapılandırma dosyasının [spring/objects] bölümü.

[spring/objects] bölümünde, artık alıştığımız Spring sözdizimini görüyoruz.

[App.config] dosyasının <objects>... </objects> bölümünde, 3 katmanlı uygulamamız için iki olası yapılandırma tanımladık:

  • biri, arayüz uygulamalarının 1. sürümünü kullanıyor
  • diğeri ise aynı arayüzlerin 2. sürümünü kullanan yapılandırma

Peki, [App.config] dosyasını nasıl kullanabiliriz?

Aşağıdaki kod, önceki [App.config] dosyasını kullanan bir konsol uygulamasını göstermektedir:

Imports System
Imports Spring.Context
Imports System.IO
Imports NUnit.Framework
Imports istia.st.spring3tier.control
Imports istia.st.spring3tier.domain
Imports System.Configuration

Namespace istia.st.springioc.tests

    Module MainTestSpring3tier

        Public Sub main()
             ' singletonları almamızı sağlayacak Spring bağlamı
            Dim contexte As IApplicationContext = CType(ConfigurationSettings.GetConfig("spring/context"), IApplicationContext)
             ' IControl arayüzünün ilk bir uygulamasını alıyoruz
            Dim control1 As IControl = CType(contexte.GetObject("control1"), IControl)
             ' sınıfı kullanıyoruz
            Dim a1 As Integer = 10, b1 As Integer = 20
            Console.WriteLine("res1({0},{1})={2}", a1, b1, control1.doSomethingInControlLayer(a1, b1))
             ' IControl arayüzünün başka bir uygulamasını alıyoruz
            Dim control2 As IControl = CType(contexte.GetObject("control2"), IControl)
             ' sınıfı kullanılır
            Dim a2 As Integer = 10, b2 As Integer = 20
            Console.WriteLine("res2({0},{1})={2}", a2, b2, control2.doSomethingInControlLayer(a2, b2))
             ' duraklama
            Console.WriteLine("Tapez [entrée] pour continuer...")
            Console.ReadLine()
        End Sub

    End Module
End Namespace

Açıklamalar:

  • Şimdiye kadar kullandığımız NUnit örneklerinde, ihtiyacımız olan tekil nesneleri elde etmek için [XmlObjectFactory] nesnesini kullanıyorduk. Burada kullanılan nesne, bir Spring arayüzü olan [IApplicationContext] türündedir. Bu nesne, [App.config]'ten, geleneksel olarak .NET'te yapılandırma dosyalarını işlemek için kullanılan [ConfigurationSettings] sınıfı aracılığıyla elde edilir.
  • [spring/context] bölümünün yöneticisi istenir. [App.config] dosyasına bakıldığında, bu dosyanın [XmlApplicationContext] türünde olduğu ve [App.config] dosyasının [spring/objects] bölümünü yönetmekle görevli olduğu görülür.
  • [IApplicationContext] türündeki nesne alındıktan sonra, bu nesne şimdiye kadar kullandığımız [XmlObjectFactory] nesnesi gibi kullanılır.

Önceki programın adı [MainTestSpring3tier.vb]'tir ve [tests] paketinde yer almaktadır:

Image

[spring3tier] projesi, [MainTestSpring3tier] için şu şekilde yapılandırılmıştır:

Image

Projenin çalıştırılması aşağıdaki sonuçları verir:

res1(10,20)=34
res2(10,20)=-10
Tapez [entrée] pour continuer...

7.8. Conclusion

Spring çerçevesi, hem uygulama mimarisinde hem de yapılandırmalarında gerçek bir esneklik sağlar. Spring'in iki temel unsurundan biri olan IoC kavramını kullandık. Diğer temel unsur ise, burada ele almadığımız AOP (Aspect Oriented Programming) kavramıdır. Bu kavram, sınıf kodunu değiştirmeden yapılandırma yoluyla bir sınıf yöntemine "davranış" eklemeye olanak tanır. Basitçe ifade etmek gerekirse, AOP belirli yöntemlere yapılan çağrıları filtrelemeye olanak tanır:

  • Filtre, hedef M yönteminden önce, sonra veya her ikisinde de çalıştırılabilir.
  • M yöntemi bu filtrelerin varlığından haberdar değildir. Bu filtreler Spring yapılandırma dosyasında tanımlanır.
  • M yönteminin kodu değiştirilmez. Filtreler, oluşturulacak Java sınıflarıdır. Spring, özellikle SGBD işlemlerini yönetmek için önceden tanımlanmış filtreler sağlar.
  • Filtreler, bean'lerdir ve bu nedenle Spring yapılandırma dosyasında bean'ler olarak tanımlanırlar.

Yaygın olarak kullanılan bir filtre, işlem filtresidir. İş katmanındaki, veriler üzerinde birbirinden ayrılamaz iki işlem (iş birimi) gerçekleştiren bir M yöntemini ele alalım. Bu yöntem, bu iki işlemi gerçekleştirmek için DAO katmanındaki M1 ve M2 adlı iki yöntemi çağırır.

İş katmanında yer aldığı için M yöntemi, bu verilerin depolandığı ortamı göz ardı eder. Örneğin, verilerin bir SGBD'te olduğunu varsaymak zorunda değildir ve M1 ile M2 yöntemlerine yapılan iki çağrıyı bir SGBD işlemi içine yerleştirmesi gerekmez. Bu ayrıntılarla ilgilenmek DAO katmanının görevidir. Bu soruna bir çözüm olarak, DAO katmanında, M1 ve M2 yöntemlerini kendisi çağıran bir yöntem oluşturulabilir; ve bu çağrıları SGBD işlemine dahil etmesi.

AOP filtreleme çözümü daha esnektir. Bu çözüm, M çağrısından önce bir işlem başlatacak ve çağrıdan sonra duruma göre bir commit veya rollback gerçekleştirecek bir filtre tanımlamaya olanak tanır.

Bu yaklaşımın birçok avantajı vardır:

  • filtre bir kez tanımlandıktan sonra, örneğin işlem gerektiren tüm yöntemler gibi birden fazla yönteme uygulanabilir
  • bu şekilde filtrelenen yöntemlerin yeniden yazılmasına gerek kalmaz
  • kullanılacak filtreler yapılandırma yoluyla tanımlandığından, bunlar değiştirilebilir

Daha fazla bilgi için: http://www.springframework.net.