2. Spring Çerçevesi'ne Giriş
Spring, 2004 yılında ilk olarak bir nesne konteyneri olarak ortaya çıktı. O zamandan beri birçok dalda gelişme gösterdi: Spring MVC, Spring Data, Spring Batch, ... [http://spring.io]. Bu bölümde sadece nesne konteynerini ele alacağız. İşte birkaç temel bilgi:
- Bir uygulama birden fazla sınıfa sahiptir ve bunlardan bazıları, benzersiz olması gereken nesneleri (singletonlar) paylaşır. Spring bu singletonları oluşturur ve yönetir;
- Spring, bu singletonları "bağlam" adı verilen bir yapıya yerleştirir;
- sınıflar, adları, türleri veya her ikisi aracılığıyla Spring’ten talep ederek uygulamanın singletonlarına erişebilir;
- Spring, singletonları oluşturur ve olası bağımlılıklarını yönetir: bir singleton, bir veya daha fazla başka singletona referans verebilir. Spring bir singleton oluşturduğunda, bunların bağımlılıklarını da oluşturur;
- Spring'e dayalı bir uygulama başlatıldığında, Spring'den uygulamanın tüm singletonlarını oluşturmasını isteyebilir. Bunlar daha sonra Spring bağlamında kullanılabilir hale gelir;
- Spring, katmanlı mimarilerin kullanımını ve arayüz tabanlı programlamayı kolaylaştırır. Basit durumlarda, her katman bir singleton tarafından uygulanır ve bir arayüzü uygular. Uygulama, katmanların uygulama sınıflarıyla değil, arayüzleriyle çalışıyorsa, aşağıdaki iki özellik sayesinde diğer katmanları değiştirmeden bir katmanın uygulamasını değiştirebilen ölçeklenebilir bir mimari elde edilir:
- uygulama, katmana adını kullanarak bir referans alır. Spring, katmanı uygulayan sınıfa ait bir referans sağlar;
- uygulama bu referansı bir sınıfın referansı olarak değil, katmanın arayüzünün referansı olarak kullanır;
Singletonların bildirilmesi, birbiriyle birleştirilebilen üç farklı şekilde yapılabilir:
- bir XML dosyası içinde,
- özel bir yapılandırma sınıfında;
- herhangi bir sınıfta anotasyonlar kullanılarak;
Aşağıda üç yapılandırma örneği sunuyoruz:
- [exemple-01]: tek bir XML dosyasında merkezi yapılandırma;
- [exemple-02]: tek bir Java sınıfında merkezi yapılandırma;
- [exemple-03]: Birden fazla Java sınıfına dağıtılmış yapılandırma;
Son örnek olan [exemple-04], katmanlı bir mimarinin Spring yapılandırmasına odaklanmaktadır. Bu, en önemli örnektir. Belgedeki mimarileri yapılandırmak için sürekli olarak bu örnek kullanılacaktır.
Bu dört örnek, aşağıdakilerin temellerini oluşturur:
- Spring yapılandırması ve bağımlılık enjeksiyonu;
- bir projenin bağımlılıklarını yönetmek için Maven kullanımı;
- projeleri test etmek için JUnit kullanımı;
2.1. Çalışma ortamının kurulması
Şunlara sahip olmanız gerekir:
- JDK (Java Development Kit) kurulu olmalıdır (paragraf 23.1);
- Maven bağımlılık yöneticisini kurmuş olmalısınız (23.2. paragraf);
- IDE Spring Tool Suite (STS) kurulu olmalıdır (paragraf 23.3);
- [http://tahe.developpez.com/java/spring-database] belgesinin kodlarını indirdiniz;
Örnekler klasöründeki [eclipse config] dosyasının çalıştırma yapılandırmalarını STS dosyasına aktarın. Bu yapılandırmalar özellikle önemlidir. Bazı projelerin çalıştırılması için JVM dosyasına argümanlar aktarılması gerekir ve bu tür yapılandırmalar genellikle baş ağrıtıcıdır. Ayrıca, bu belgede Maven projeleri kullanılmaktadır. Şu uyarıyla karşılaştığınızda:
Not: Tüm Maven projelerini yeniden oluşturmak için [Alt-F5] komutunu çalıştırın.
Bu uyarıya uymanız şiddetle tavsiye edilir. Bu önlem alınmazsa, projeler arasında Maven bağımlılıklarının hatalı olması nedeniyle anlaşılmaz hatalar ortaya çıkabilir.
![]() |
- komutunu [1] olarak değiştirin, [Package Explorer] dosyasına sağ tıklayın;
![]() |
- [4a-4b-4c]'te, örneklerin bulunduğu [eclipse config / launch configurations] ve [4b] klasörlerini seçin;
- [5]'te mevcut yapılandırmalar. Hepsini seçin;
- 6'te sihirbazı tamamlayın;
- [7-8]'te, içe aktarılan yürütme yapılandırmalarını görüntüleyin;
![]() |
- [8-9]'te, [9]'in işaretini kaldırarak STS'te yüklenmemiş proje yapılandırmalarını görüntüleyin. Şu anda durum budur;
![]() |
- [10]'te Java uygulamaları ve [11]'te inceleyeceğimiz ilk üç örneğin çalıştırma yapılandırmaları;
- [12]'te JUnit testleri ve [13]'te bu paragrafın dördüncü örneğinin çalıştırma yapılandırması;
Şimdi, Maven yerel depo klasörünü belirtecek olan [M2_REPO] adlı bir Eclipse değişkeni oluşturun (bkz. paragraf 23.2). Bu değişken, birkaç yürütme yapılandırmasında kullanılır:
![]() |
[M2_REPO] değişkenine, aşağıda 6 olarak görülen değer atanmıştır:
![]() |
Şimdi, [spring-core] klasöründeki dört örneği içe aktarın:
![]() |
- dosyasını [1] dosyasına aktarın, [Package Explorer] dosyasına sağ tıklayın;
![]() |
- dosyasını [4a-4b] dosyasına aktarın, örneklerin bulunduğu [spring-core] klasörünü seçin;
- [5]'te, klasördeki tüm projeleri seçin ve [Finish]'i oluşturun;
- 6'te, [Package Explorer]'teki dört projeyi seçin;
2.2. Exemple-01
2.2.1. Eclipse projesi
![]() |
2.2.2. [Personne] sınıfı
![]() |
package istia.st.spring.core;
public class Personne {
// alanlar
private String nom;
private String prenom;
private int age;
// yapıcılar
public Personne() {
}
public Personne(String nom, String prénom, int âge) {
this.nom = nom;
this.prenom = prénom;
this.age = âge;
}
// toString
public String toString() {
return String.format("Personne[%s, %s,%d]", prenom, nom, age);
}
// alıcı ve ayarlayıcılar
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Not: Get ve set yöntemleri aşağıdaki şekilde otomatik olarak oluşturulabilir: [1-2]:
![]() |
2.2.3. [Appartement] sınıfı
![]() |
package istia.st.spring.core;
public class Appartement {
// alanlar
private Personne proprietaire;
private int surface;
// alıcı ve ayarlayıcılar
public Personne getProprietaire() {
return proprietaire;
}
public void setProprietaire(Personne proprietaire) {
this.proprietaire = proprietaire;
}
public int getSurface() {
return surface;
}
public void setSurface(int surface) {
this.surface = surface;
}
// toString
public String toString() {
return String.format("Appartement[%s, %s]", proprietaire, surface);
}
}
Not: Bu sınıfın açık bir oluşturucusu yoktur. Bu durumda, varsayılan olarak hiçbir işlem yapmayan parametresiz oluşturucu her zaman mevcuttur. Oluşturucular oluşturulduğunda, bu varsayılan oluşturucu artık örtük olarak mevcut olmaz. Bu durumda, onu açıkça tanımlamak gerekir:
2.2.4. Spring yapılandırma dosyası
![]() |
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- Kişi 01 -->
<bean id="personne_01" class="istia.st.spring.core.Personne">
<constructor-arg index="0" value="dubois" />
<constructor-arg index="1" value="paul" />
<constructor-arg index="2" value="34" />
</bean>
<!-- Kişi 02 -->
<bean id="personne_02" class="istia.st.spring.core.Personne">
<property name="nom" value="martin" />
<property name="prenom" value="micheline" />
<property name="age" value="18" />
</bean>
<!-- kişi listesi -->
<util:list id="club">
<ref bean="personne_01" />
<ref bean="personne_02" />
</util:list>
<!-- bir daire -->
<bean id="appartement" class="istia.st.spring.core.Appartement">
<property name="surface" value="100" />
<property name="proprietaire" ref="personne_01" />
</bean>
</beans>
-
- ve 27. satırlar: singletonlar <beans> etiketinin içinde tanımlanır;
- 6-10. satırlar: Her singleton bir <bean> etiketiyle tanımlanır;
-
- satır: [id], singleton'ın tanımlayıcısıdır. [class], örneklenecek sınıfın tam adıdır;
- 7-9. satırlar: [Personne] sınıfının oluşturucusuna aktarılacak üç değer;
- satır 12-16: [Personne] sınıfı, önce varsayılan oluşturucusu [new Personne()] ile oluşturulur. Ardından her bir [property] etiketi için sınıfın bir setter yöntemi kullanılır. Örneğin 13. satırda, [setNom("martin")] yöntemi çalıştırılacaktır. Dolayısıyla [setNom] yönteminin mevcut olması gerekir. Bu, hatırlanması gereken önemli bir noktadır;
- 18-21. satırlar: <util:list> etiketi, bir liste olan bir singleton tanımlamaya olanak tanır;
-
- satır: 6. satırda tanımlanan [personne_01] singleton'ını belirtir. Burada bağımlılık enjeksiyonu olarak adlandırılan bir işlem söz konusudur. Bir singleton'ın alanını başlatmak için iki öznitelik kullanılabilir:
- [value]: alana bir temel değer (dize, sayı, tarih, ...) atamak için,
- [ref]: alana bir Spring nesnesinin referansını atamak için;
Not: Spring yapılandırma dosyası şu şekilde oluşturulabilir: [1-4]:
![]() |
2.2.5. Çalıştırılabilir sınıf
![]() |
package istia.st.spring.core;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo01 {
@SuppressWarnings({ "unchecked", "resource" })
public static void main(String[] args) {
// Spring bağlamının alınması
ApplicationContext ctx = new ClassPathXmlApplicationContext("config-01.xml");
// bean'leri alıyoruz
Personne p01 = ctx.getBean("personne_01", Personne.class);
Personne p02 = ctx.getBean("personne_02", Personne.class);
List<Personne> club = ctx.getBean("club", new ArrayList<Personne>().getClass());
Appartement appart01 = ctx.getBean(Appartement.class);
// bunların görüntülenmesi
System.out.println("personnes--------");
System.out.println(p01);
System.out.println(p02);
System.out.println("club--------");
for (Personne p : club) {
System.out.println(p);
}
System.out.println("appartement--------");
System.out.println(appart01);
// alınan bean'ler singleton'lardır
// bunlar birden çok kez istenebilir, her seferinde aynı bean alınır
Personne p01b = ctx.getBean("personne_01", Personne.class);
System.out.println(String.format("beans [p01,p01b] identiques ? %s", p01b == p01));
}
}
-
- satır: Spring bağlamını oluşturur. [config-01.xml] dosyasında tanımlanan tüm singletonlar bu aşamada örneklenir;
-
- satır: [personne_01] ile tanımlanan, [Personne] türündeki tekil nesneye ilişkin bir referans ister. Bu ikinci parametre isteğe bağlıdır; ancak bu durumda [Object] türünde bir referans alınır ve bu referansın [Personne] türüne dönüştürülmesi gerekir;
-
- satır: [Appartement] türünde yalnızca bir singleton olduğu için bean adı değil, sadece türü kullanılır;
-
- satır: İstenen singleton'un hem tanımlayıcısı hem de türü kullanılmıştır. [new ArrayList<Personne>().getClass()] türünde yalnızca bir singleton olduğu için tanımlayıcı gereksizdir;
- 32-33. satırlar: Aynı singleton'a birden fazla kez erişilirse her seferinde aynı referansın elde edildiğini gösterir; bu da karşımızdaki nesnenin gerçekten bir singleton olduğunu kanıtlar. Bu noktayı anlamak önemlidir;
Not: Çalıştırılabilir bir sınıf şu şekilde oluşturulabilir: [1-6]:
![]() |
![]() |
- 6 seçeneğinin işaretlenmesi, oluşturulan sınıfın onu çalıştırılabilir hale getirecek [main] adlı statik bir yöntem içermesini sağlar;
2.2.6. Projenin bağımlılıkları
![]() |
- Spring bağımlılıkları: [spring-core, spring-beans, spring-context, spring-expression, commons-logging];
Bağımlılıklar projeye şu şekilde eklenir:
![]() |
- [1]'te: projeye sağ tıklayın / [Build Path] / [Configure Build Path];
![]() |
- [2]'e: Eklenecek JARs dosyaları projenin bir klasöründe bulunuyorsa [Add JARs]. Aksi takdirde [Add External JARs];
![]() |
- [3]'e, projenin ClassPath dosyasına eklenecek JARs dosyalarını seçin (bu dosyalar burada projenin içindeki [lib] klasöründedir);
Tanım: Bir projenin [ClassPath]'i, projeyi çalıştıran JVM (Java Sanal Makinesi) tarafından, proje tarafından referans verilen bir sınıfı bulmak için taranan klasörlerin bütünüdür. Bir Eclipse projesi için [ClassPath], aşağıdaki öğelerden oluşur:
- projenin [bin] klasörü;
- projenin [Build Path] öğeleri;
[bin] klasörü, [src] klasörünün derlenmesi sonucu oluşturulan klasördür. Dolayısıyla, [src] klasörüne yerleştirilen her şey otomatik olarak [ClassPath]'in bir parçası olur (bir .java dosyası olmasa bile). Dolayısıyla önceki projede, [src] klasöründe bulunan spring yapılandırma dosyası [config-01.xml], projenin çalıştırılması sırasında [Classpath]'in bir parçası olacaktır.
2.2.7. Sonuçlar
2.3. Exemple-02
2.3.1. Eclipse projesi
![]() |
2.3.2. Spring yapılandırma sınıfı
package istia.st.spring.core;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
@Bean
public Personne personne_01() {
return new Personne("Paul", "Dubois", 34);
}
@Bean
public Personne personne_02() {
return new Personne("Martin", "Micheline", 18);
}
@Bean
public List<Personne> club(Personne personne_01, Personne personne_02) {
List<Personne> personnes = new ArrayList<Personne>();
personnes.add(personne_01);
personnes.add(personne_02);
return personnes;
}
@Bean
public Appartement appartement(Personne personne_01) {
Appartement appartement = new Appartement();
appartement.setSurface(200);
appartement.setPropriétaire(personne_01);
return appartement;
}
}
-
- satır: [@Configuration] anotasyonu bir Spring anotasyonudur. Bu anotasyon, anotasyonun uygulandığı sınıfın singleton'lar tanımladığını belirtir. Singleton'lar, [@Bean] anotasyonu kullanılarak tanımlanır. Spring, [@Bean] ile anotlanmış tüm yöntemleri çalıştıracaktır. Bu yöntemler, uygulamanın singletonlarını oluşturur;
- 12-15. satırlar: [personne_01] ile tanımlanan bir singleton tanımlar; yani yöntemin adı.
-
- satır: [personne_01, personne_02] parametreleri, singletonların adlarını taşır. Spring, bunları otomatik olarak bu singletonların referanslarıyla başlatacaktır. Buna parametre enjeksiyonu denir;
Singleton'ları bu şekilde yapılandırmak, XML dosyasını kullanan yöntemden daha açıktır. Aslında, Spring'in XML dosyasından dolaylı olarak yaptığı şeyi kendimiz tekrarlıyoruz.
2.3.3. Çalıştırılabilir sınıf
![]() |
package istia.st.spring.core;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Demo02 {
@SuppressWarnings({ "unchecked", "resource" })
public static void main(String[] args) {
// Spring bağlamı alınır
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
// bean'leri alıyoruz
Personne p01 = ctx.getBean("personne_01", Personne.class);
Personne p02 = ctx.getBean("personne_02", Personne.class);
List<Personne> club = ctx.getBean("club", new ArrayList<Personne>().getClass());
Appartement appart01 = ctx.getBean(Appartement.class);
// bunlar görüntülenir
System.out.println("personnes--------");
System.out.println(p01);
System.out.println(p02);
System.out.println("club--------");
for (Personne p : club) {
System.out.println(p);
}
System.out.println("appartement--------");
System.out.println(appart01);
// Alınan bean'ler singleton'lardır
// bunları birden çok kez talep edebiliriz, her zaman aynı bean alınır
Personne p01b = ctx.getBean("personne_01", Personne.class);
System.out.println(String.format("beans [p01,p01b] identiques ? %s", p01b == p01));
}
}
-
- satır, [Config] sınıfında tanımlanan tüm bean'lerin örneklenmesini sağlar;
- kodun geri kalanında değişiklik yoktur;
2.3.4. Projenin bağımlılıkları
![]() | ![]() |
Bağımlılıklar, aşağıdaki [pom.xml] dosyası tarafından belirlenir:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>istia.st.spring.core</groupId>
<artifactId>spring-core-02</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-core-02</name>
<description>Introduction à Spring</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
</dependencies>
<!-- eklentiler -->
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
Bağımlılıkları bilinmeyen Java kütüphaneleri kullanıldığında, bir projenin bağımlılıklarını manuel olarak yönetmek baş ağrıtıcı bir iş haline gelir. Örneğin, veritabanlarına erişimi yöneten [Hibernate] çerçeve programı onlarca bağımlılığa sahiptir. [Maven] projesi bu sorunu çözer. İhtiyacımız olan bağımlılığın adını belirtiriz. Bu bağımlılık, internette bulunan Maven depolarında otomatik olarak aranır. İstenen bağımlılığın kendisinin de bağımlılıkları varsa, bunlar da otomatik olarak indirilir. İndirilen bu bağımlılıklar, bilgisayardaki yerel bir depoda saklanır. Daha sonra başka bir uygulama aynı bağımlılığa ihtiyaç duyarsa, bu bağımlılık yeniden indirilmez, yerel depoda aranır. Bir bağımlılık aşağıdaki öğelerle tanımlanır:
-
- satır: bir <dependency> etiketi;
-
- satır: genellikle bağımlılığı oluşturan şirketi tanımlayan bir [groupId] özniteliği;
-
- satır: bağımlılığı tanımlayan bir [artifactId] özniteliği;
-
- satır: istenen sürümü tanımlayan bir [version] özniteliği;
Projenin derlenmesi, 4-8. satırlarda tanımlanan bir Maven bileşenini oluşturacaktır:
- 4-6. satırlar: az önce tanımladığımız [ groupId, artifactId,version] öznitelikleri;
- 7-8. satırlar: isteğe bağlı öznitelikler;
24-40. satırların rolüne biraz sonra tekrar değineceğiz. Sıradan bir Eclipse projesini bir Maven projesine dönüştürmek için iki şey yapmanız gerekir:
- yukarıdaki [pom.xml] dosyasını oluşturmak;
- projenin artık bir Maven projesi olduğunu belirtmek [1-4]:
![]() |
Bir Maven projesinin simgesinde M [4] harfleri bulunur. S harfi, projenin Spring bileşenleri içerdiğini gösterir. Bir Eclipse projesini (az önce yaptığımız gibi) Maven projesine dönüştürmek tavsiye edilmez; çünkü bu durumda proje, bir Maven projesinden beklenen yapıya sahip olmaz ve bu da bazen beklenmedik sorunlara yol açabilir.
2.3.5. Projenin Maven artefaktının oluşturulması
Projenin Maven artefaktı, [pom.xml] dosyasının 4-6. satırlarında tanımlanan öğedir:
<groupId>istia.st.spring.core</groupId>
<artifactId>spring-core-02</artifactId>
<version>0.0.1-SNAPSHOT</version>
Bu artefaktı oluşturmak için, [pom.xml] dosyasında aşağıdaki 3-7. satırların bulunması gerekir:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
Bu satırlar, projenin artefaktını oluşturabilen Maven eklentisini tanımlar. Ardından şu şekilde ilerlenir:
![]() |
Bu şekilde oluşturulan artefakt, yerel Maven deposuna eklenir. Deponun konumu Eclipse yapılandırmasında bulunabilir:
![]() |
Böylece, Maven artefaktının doğru şekilde kurulup kurulmadığını kontrol etmek mümkündür:
![]() |
Artık başka bir yerel Maven projesi bu arşivi kullanabilir.
2.4. Exemple-03
2.4.1. Eclipse Projesi
Bu sefer [1-8] adlı bir Maven projesi oluşturuyoruz:
![]() |
![]() |
- [3b]: projenin oluşturulacağı boş bir klasör seçin;
![]() |
- [4]: projenin ait olacağı Maven grubunun kimliği;
- [5] olarak: Oluşturulan Maven artefaktının adı:
- [7]'te: paketleme türü (war, ear, apk vb. seçenekler de mevcuttur);
- [8]: bu şekilde oluşturulan proje;
Bir Maven projesi varsayılan olarak belirli bir dizin yapısına sahiptir:
- [src / main / java]: projenin kaynak kodları. Bu kaynaklardan derlenen dosyalar, projenin [target/classes] klasörüne yerleştirilecektir;
- [src / main / resources]: Java kaynakları olmasa da projenin Classpath'inde bulunması gereken kaynaklar. Bunlar olduğu gibi projenin [target/classes] klasörüne kopyalanacaktır;
- [src / test / java]: Projenin test kaynak kodları. Bu kaynak kodlardan derlenen dosyalar, projenin [target/test-classes] klasörüne yerleştirilecektir. Bu öğeler, projenin Maven arşivine dahil edilmez;
- [src / test / resources]: Testler için projenin Classpath'inde bulunması gereken, ancak Java kaynakları olmayan kaynaklar. Bunlar olduğu gibi projenin [target/test-classes] klasörüne kopyalanacaktır;
Projeyi şu şekilde tamamlıyoruz:
![]() |
2.4.2. Maven yapılandırması
Varsayılan olarak bir [pom.xml] dosyası oluşturulur. Bu dosyayı şu şekilde değiştiriyoruz:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>istia.st.spring.core</groupId>
<artifactId>spring-core-03</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-core-03</name>
<description>Introduction à Spring</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<!-- üst Maven projesi -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- günlükler -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
</dependencies>
<!-- eklentiler -->
<build>
<plugins>
<!-- proje arşivini bağımlılıklarıyla birlikte oluşturmak için -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<!-- proje artefaktının yerel Maven deposuna yüklenmesi için -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
</project>
-
- satır: proje UTF-8 ile kodlanmıştır;
-
- satır: Projeyi derlemek için JDK 1.8 kullanılır;
- satır 16-20: Spring kütüphanelerini kullanan projeler için, [spring-boot-starter-parent] adlı bir üst Maven projesi kullanmak pratiktir. Bu proje, çeşitli Spring kütüphanelerinin sürümlerini ve bunların bağımlılıklarının sürümlerini tanımlar. Bu sayede, bunları bağımlılık tanımında tekrar belirtmek gerekmez. Bu nedenle 24-27. satırlarda istenen [spring-context] sürümü belirtilmez. Bu, üst proje [spring-boot-starter-parent] tarafından tanımlanan sürüm olacaktır. Bu teknik, bağımlılıklar arasındaki olası sürüm uyumsuzlukları konusunda endişelenmenize gerek kalmamasını sağlar. Üst proje tarafından tanımlanan sürümler birbirleriyle uyumludur;
- 29-32. satırlar: Spring, bir log kütüphanesi aracılığıyla konsola önemli miktarda bilgi yazdırır. Bu kütüphane burada içe aktarılmıştır;
- 40-47. satırlar: Daha sonra tekrar ele alacağımız bir Maven eklentisi;
- 50-52. satırlar: projenin Maven artefaktını oluşturan eklenti;
2.4.3. Spring yapılandırma sınıfı
![]() |
[Config] sınıfı şu şekildedir:
package istia.st.spring.core.config;
import istia.st.spring.core.entities.Personne;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan({ "spring.core.entities" })
public class Config {
@Bean
public Personne personne_01() {
return new Personne("Paul", "Dubois", 34);
}
@Bean
public Personne personne_02() {
return new Personne("Martin", "Micheline", 18);
}
@Bean
public List<Personne> club(Personne personne_01, Personne personne_02) {
List<Personne> personnes = new ArrayList<Personne>();
personnes.add(personne_01);
personnes.add(personne_02);
return personnes;
}
@Bean
public int mySurface() {
return 200;
}
}
- Burada, iki yeni değişiklik içeren, önceden yorumlanmış bir kod bulunmaktadır:
-
- satır: [spring.core.entities] paketinde örneklenmesi gereken başka bean'ler olduğunu belirtir,
- 34-37. satırlar: bir [mySurface] bean'i;
-
2.4.4. [Appartement] sınıfı
![]() |
package spring.core.entities;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class Appartement {
// Spring tarafından enjekte edilen alanlar
@Autowired
@Qualifier("personne_01")
private Personne propriétaire;
@Autowired
@Qualifier("mySurface")
private int surface;
// getter ve setter'lar
public Personne getPropriétaire() {
return propriétaire;
}
public void setPropriétaire(Personne propriétaire) {
this.propriétaire = propriétaire;
}
public int getSurface() {
return surface;
}
public void setSurface(int surface) {
this.surface = surface;
}
// toString
public String toString() {
return String.format("Appartement[%s, %s]", propriétaire, surface);
}
}
-
- satır: [@Component] anotasyonu, Spring'e bu sınıfın, çerçevenin örneklendirmesi ve yönetmesi gereken bir singleton olduğunu belirtir. [Config] sınıfında [@ComponentScan({ "istia.st.spring.core.entities" })] yazdığımız için bu singleton bulunacaktır;
-
- satır: Spring’den alana singletonlardan birinin referansını enjekte etmesini ister. Bu referans iki şekilde tanımlanabilir:
- kimliği ile (12. ve 16. satırlar),
- bu türe sahip tek bir singleton varsa, türüyle;
2.4.5. Projenin çalıştırılması
Projenin çalıştırılması sonucunda konsolda şu çıktı görüntülenir:
- 1-3. satırlar: Spring, onlarca satırdan oluşan çok sayıda günlük kaydı üretir. Bu günlük kayıtları, çalışmayan bir projenin hata ayıklamasında çok yararlı olabilir. Proje çalıştığında, günlük kayıtları şu şekilde azaltılabilir:
![]() |
[src / main / resources] klasöründe aşağıdaki [logback.xml] dosyasını oluştururuz:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- kodlayıcılara varsayılan olarak tür atanır
ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- günlük düzey kontrolü -->
<root level="info"> <!-- bilgi, hata ayıklama, uyarı -->
<appender-ref ref="STDOUT" />
</root>
</configuration>
-
- satırda, günlüklerin seviyesi belirlenir. [debug] çok ayrıntılı bir seviyedir, [info] ise çok daha az ayrıntılıdır;
İşte [level=info] ile elde edilen sonuçlar:
Artık sadece bir satır günlük kaydı var.
2.4.6. Bağımlılıklarıyla birlikte proje arşivinin oluşturulması
Önceki projede oluşturulan arşiv, Maven kullanmayan bir Eclipse projesi tarafından da kullanılabilir. Bazı projeler çok sayıda kütüphane kullanır ve bunlardan hiçbirini unutmamak zor olabilir. İşte burada Maven harikalar yaratır; çünkü en üst düzeydeki bağımlılığı belirtmek yeterlidir, daha alt düzeydeki diğer bağımlılıklar projenin Classpath'ine otomatik olarak eklenir. Maven kullanmayan bir Eclipse projesinin bir Maven projesinin arşivlerini kullanması gerektiğinde, bu projenin tüm bağımlılıklarıyla birlikte artefaktını oluşturmak mümkündür (önceki projede bu mümkün değildi). Bu oluşturma işlemi için, [pom.xml] dosyasında aşağıdaki 3-10. satırların bulunması gerekir:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
</plugins>
</build>
Bu satırlar, projenin artefaktını bağımlılıklarıyla birlikte oluşturabilen Maven eklentisini tanımlar. Ardından şu şekilde ilerlenir: [1-6]:
![]() |
![]() |
- [4-6], bir Maven yürütme yapılandırmasını temsil eder;
- [4]'e herhangi bir ad girin;
- [5]'e proje klasörünü belirtin;
- 6'e Maven hedeflerini (goals) girin:
- [clean]: projenin [target] klasörü silinir;
- [compile]: proje derlenir. Derleme çıktıları, yeniden oluşturulan [target] klasörüne yerleştirilir;
- [assembly:single]: Projenin ve bağımlılıklarının sınıfları, [target] klasöründeki tek bir jar arşivine yerleştirilir;
Çalıştırma sonrasında şu sonuç elde edilir:
![]() |
Bir jar arşivi, bir sıkıştırma programı ile açılabilen sıkıştırılmış bir dosyadır. Yukarıdaki arşiv açıldığında, aşağıdaki dizin yapısı elde edilir:
- [8] içinde, projenin bağımlılık sınıfları;
- [9] içinde, projenin kendisinin sınıfları;
2.5. Exemple-04
2.5.1. Amaç
Bu örnek, [Introduction à Spring IoC] belgesinde sunulan örneklerden birini ele almaktadır; bu belgede, çok katmanlı mimarilerin yapılandırılmasında Spring'in sağladığı faydalar gösterilmektedir. Orijinal belgede, örnek XML dosyasıyla oluşturulan bir Spring yapılandırmasıyla ele alınmaktadır. Burada ise örneği Java sınıfları ve anotasyonlar kullanılarak yapılan bir yapılandırma ile ele alıyoruz.
Burada, aşağıdaki mimari için bir Spring projesini yapılandırmak istiyoruz:
![]() |
Her katman, iki sınıfla uygulanan bir arayüze sahiptir. Spring sayesinde, diğer katmanların koduna hiçbir etki yaratmadan bir katmanın uygulamasını değiştirebileceğimizi göstermek istiyoruz.
2.5.2. Eclipse projesi
2.5.2.1. Génération
Yeni bir proje türü oluşturuyoruz:
![]() |
![]() |
- [4]'te Eclipse projesinin adını girin;
- [5]'te bir Maven projesi seçin;
- 6'te, Java sürümünü >=1.7 olarak seçin;
- [7]'te, önerilen Spring Boot sürümünü seçin;
- [8-11]'teki bilgiler Maven bilgileridir;
- [12]'te, önerilen bağımlılıklardan bir veya birkaçını seçebilirsiniz. Bu, Maven'ın [pom.xml] dosyasına bir dizi bağımlılığın eklenmesini sağlayacaktır;
![]() |
- [13] dosyasında, projeyi barındıracak mevcut ve boş bir klasör belirtin;
- [14] dosyasında ise oluşturulan proje yer alır. Şimdi bu öğeleri ayrıntılı olarak inceleyeceğiz;
Proje, aşağıdaki [pom.xml] dosyası ile yapılandırılmış bir Maven projesidir:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>istia.st.spring.core</groupId>
<artifactId>spring-core-04</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-core-04</name>
<description>Programmation par interfaces</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
<relativePath/> <!-- depo'dan üst öğeyi arama -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>demo.SpringCore04Application</start-class>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 6-12. satırlar: proje oluşturma sihirbazında girilen bilgileri içerir;
- 14-19. satırlar: Bir dizi kütüphaneyi sürümleriyle birlikte tanımlayan üst Maven projesidir. Bunlardan herhangi biri projenin bir bağımlılığıysa, [pom.xml] dosyasında sürümü belirtilmeden listelenir;
- 23. satır: Bu satır, yalnızca projenin çalıştırılabilir bir arşivi oluşturulacaksa kullanılır. Aksi takdirde kullanılmaz;
- satır 28-31: Bir Spring Boot projesinin minimum bağımlılığı. Hatırlatmak gerekirse, onay kutularından hiçbir bağımlılığı seçmedik;
- satır 33-37: Spring ile entegre JUnit ve [http://junit.org/] birim testlerini yönetmek için gerekli bağımlılık. Satır 36, bu bağımlılığın yalnızca testler için gerekli olduğunu belirtir. Dolayısıyla, proje arşivine dahil edilmeyecektir;
- satır 42-45: projenin Maven artefaktını oluşturmaya yarayan eklenti;
Bu dosya tarafından getirilen bağımlılık listesi şöyledir: [1]:
![]() |
Göreceğiz ki bunlar burada yapmak istediğimiz şey için yeterlidir.
2.5.2.2. Çalıştırılabilir sınıf
![]() |
[SpringCore04Application] [produit[0,3], produit[1,4]] yürütülebilir sınıfı şu şekildedir:
package demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringCore04Application {
public static void main(String[] args) {
SpringApplication.run(SpringCore04Application.class, args);
}
}
- 6. satırda, [@SpringBootApplication] anotasyonu, üç [@Configuration, @EnableAutoConfiguration, @ComponentScan] anotasyonunun kısayoludur; bu da şu anlama gelir:
- [SpringCore04Application] sınıfı bir Spring yapılandırma sınıfıdır;
- Spring Boot'tan, projenin Classpath'inde, yani burada Maven bağımlılıklarında bulacağı sınıflardan yapılandırmalar yapması istenir;
- geçerli klasörü ([SpringCore04Application] sınıfının bulunduğu klasör) inceleyerek, orada olası diğer Spring bileşenlerini bulması;
- 10. satır: [SpringApplication.run] statik yöntemi yürütülür. Bu yöntemin ilk parametresi bir Spring yapılandırma sınıfıdır; burada bu sınıf [SpringCore04Application]’tir. İkinci parametresi ise burada [main] yöntemine (9. satır) aktarılan argümanların listesidir. [SpringApplication.run] statik yönteminin görevi, Spring bağlamını oluşturmaktır; yani, ya yapılandırma sınıflarında ya da [@ComponentScan] anotasyonu tarafından taranan klasörlerde bulunan çeşitli bean'leri oluşturmaktır. Buradaki [main] yöntemi başka bir şey yapmaz. Bu yönteme biraz daha anlam kazandırmak için onu şu şekilde değiştireceğiz:
package demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class SpringCore04Application {
public static void main(String[] args) {
// Spring bağlamının oluşturulması
ConfigurableApplicationContext context = SpringApplication.run(SpringCore04Application.class, args);
// bağlamın görüntülenmesi
System.out.println("---------------- Liste des beans Spring");
for (String beanName : context.getBeanDefinitionNames()) {
System.out.println(beanName);
}
// bağlamın kapatılması
context.close();
}
}
- 12. satır: statik [SpringApplication.run] yöntemi, oluşturduğu Spring bağlamını döndürür;
- 15-17. satırlar: Bu bağlamdaki tüm bean'lerin adları görüntülenir;
Uygulamayı şu şekilde çalıştırabiliriz: [1-3]. Her zamanki yöntem olan [Run As Java Application] de geçerlidir.
![]() |
Aşağıdaki sonuç elde edilir:
- 14-28. satırlar: Spring bağlamındaki bean'ler. Bunların rolünü bilmiyoruz. 18. satırda [springCore04Application] bean'ini görüyoruz; bu bean, [@SpringBootApplication] anotasyonu sayesinde otomatik olarak bir Spring bean'i haline geliyor;
- diğer satırlar ise [INFO] seviyesindeki Spring günlükleridir. Daha önce gördüğümüz gibi, bu günlükler projenin Classpath'inde bulunan [logback.xml] dosyası ile kontrol edilebilir:
![]() |
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- kodlayıcılara varsayılan olarak tür atanır
ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- günlük düzeyinin kontrolü -->
<root level="warn"> <!-- bilgi, hata ayıklama, uyarı -->
<appender-ref ref="STDOUT" />
</root>
</configuration>
Yukarıdaki 12. satırda, [info] yerine [warn] seviyesini yazarsak, şu sonucu elde ederiz:
Günlükler kayboldu. Yalnızca [warn] seviyesindeki mesajlar görünüyor ve burada böyle bir mesaj yoktu.
2.5.3. Mimarinin farklı katmanlarının uygulanması
![]() |
Şimdi yukarıdaki mimarinin üç katmanını uygulayacağız:
![]() |
[DAO] katmanı, [spring.core.dao] paketi tarafından uygulanır. Aşağıdaki [IDao] arayüzünü sunar:
package spring.core.dao;
public interface IDao {
public int doSomethingInDaoLayer(int a, int b);
}
Bu arayüzün iki uygulaması vardır: [Dao1] ve [Dao2]:
package spring.core.dao;
public class Dao1 implements IDao {
public int doSomethingInDaoLayer(int a, int b) {
return a+b;
}
}
package spring.core.dao;
public class Dao2 implements IDao {
public int doSomethingInDaoLayer(int a, int b) {
return a-b;
}
}
[métier] katmanı, [spring.core.metier] paketi tarafından uygulanmaktadır. Aşağıdaki [IMetier] arayüzünü sunar:
package spring.core.metier;
public interface IMetier {
public int doSomethingInMetierLayer(int a, int b);
}
Bu arayüzün iki uygulaması vardır: [Metier1] ve [Metier2]:
package spring.core.metier;
import spring.core.dao.IDao;
public class Metier1 implements IMetier {
private IDao dao;
public int doSomethingInMetierLayer(int a, int b) {
a++;
b++;
return dao.doSomethingInDaoLayer(a, b);
}
public void setDao(IDao dao) {
this.dao = dao;
}
}
package spring.core.metier;
import spring.core.dao.IDao;
public class Metier2 implements IMetier {
private IDao dao;
public int doSomethingInMetierLayer(int a, int b) {
a--;
b++;
return dao.doSomethingInDaoLayer(a, b);
}
public void setDao(IDao dao) {
this.dao = dao;
}
}
[UI] katmanı, [spring.core.ui] paketi tarafından uygulanmaktadır. Aşağıdaki [IUi] arayüzünü sunar:
package spring.core.ui;
public interface IUi {
public int doSomethingInUiLayer(int a, int b);
}
Bu arayüzün iki uygulaması vardır: [Ui1] ve [Ui2]:
package spring.core.ui;
import spring.core.metier.IMetier;
public class Ui1 implements IUi {
private IMetier metier;
public int doSomethingInUiLayer(int a, int b) {
a++;
b++;
return metier.doSomethingInMetierLayer(a, b);
}
public void setMetier(IMetier metier) {
this.metier = metier;
}
}
package spring.core.ui;
import spring.core.metier.IMetier;
public class Ui2 implements IUi {
private IMetier metier;
public int doSomethingInUiLayer(int a, int b) {
a--;
b++;
return metier.doSomethingInMetierLayer(a, b);
}
public void setMetier(IMetier metier) {
this.metier = metier;
}
}
2.5.4. Spring projesinin yapılandırılması
![]() |
[Config] yapılandırma sınıfı şu şekildedir:
package spring.core.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.core.dao.Dao1;
import spring.core.dao.Dao2;
import spring.core.dao.IDao;
import spring.core.metier.IMetier;
import spring.core.metier.Metier1;
import spring.core.metier.Metier2;
import spring.core.ui.IUi;
import spring.core.ui.Ui1;
import spring.core.ui.Ui2;
@Configuration
public class Config {
// -------------- [Ui1, Metier1, Dao1] uygulaması
@Bean
public IDao dao1() {
return new Dao1();
}
@Bean
public IMetier metier1(IDao dao1) {
Metier1 metier = new Metier1();
metier.setDao(dao1);
return metier;
}
@Bean
public IUi ui1(IMetier metier1) {
Ui1 ui = new Ui1();
ui.setMetier(metier1);
return ui;
}
// -------------- uygulama [Ui2, Metier2, Dao2]
@Bean
public IDao dao2() {
return new Dao2();
}
@Bean
public IMetier metier2(IDao dao2) {
Metier2 metier = new Metier2();
metier.setDao(dao2);
return metier;
}
@Bean
public IUi ui2(IMetier metier2) {
Ui2 ui = new Ui2();
ui.setMetier(metier2);
return ui;
}
}
- 20-23. satırlar: [dao1] adlı bean (yöntem adı), [Dao1] sınıfının (22. satır) bir örneğidir ve bu sınıf, [IDao] arayüzünün bir uygulaması olarak kabul edilir (21. satır) arayüzünün bir uygulaması olarak kabul edilir. Dolayısıyla [dao1] bean'i, bir sınıf örneği değil, bir arayüz örneği olarak görülür (terminoloji yanlış olsa da anlaşılabilir). Bu, anlaşılması gereken önemli bir noktadır. Diğer tüm bean'ler de arayüz örnekleri olacaktır;
- 25-30. satırlar: [Metier1] sınıfı tarafından uygulanan [IMetier] arayüzünün bir örneği;
- satır 32-37: [IUi] arayüzünün, [Ui1] sınıfı tarafından uygulanan bir örneği;
- satır 20-37: [UI, Metier, DAO] katmanlarını [Ui1, Metier1, Dao1] örnekleriyle uygular;
- satır 40-57: [UI, Metier, DAO] katmanlarını [Ui2, Metier2, Dao2] örnekleriyle uygular;
2.5.5. [JUnitTest] birim testi
![]() |
[JUnitTest] sınıfı, Maven projesinin [src / test / java] dalına yerleştirilmiştir. Bu daldaki öğeler, projenin nihai arşivine dahil edilmez. Kod şöyledir:
package spring.core.tests;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import spring.core.config.Config;
import spring.core.dao.IDao;
import spring.core.metier.IMetier;
import spring.core.ui.IUi;
@SpringApplicationConfiguration(classes = { Config.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class JUnitTest {
...
}
- 16. satır: [@SpringApplicationConfiguration] anotasyonu, Spring Boot Test projesine ait bir anotasyondur (8. satır). Bu anotasyon, [pom.xml] dosyasının aşağıdaki bağımlılığı tarafından eklenmiştir:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
Bu anotasyonun parametresi, test için gerekli Spring bağlamını oluşturmak üzere kullanılacak yapılandırma sınıflarının listesidir. Burada, daha önce tanıtılan [Config] yapılandırma sınıfını kullanıyoruz;
- 17. satır: [@RunWith] anotasyonu, JUnit anotasyonudur (5. satır). Bu anotasyonun parametresi, Junit çerçevesinin varsayılan sınıfı yerine testleri yürütmekle görevli sınıftır. Bu sınıf bir Spring sınıfıdır (9. satır). Test sınıfında bulunan Spring anotasyonlarını kullanacaktır;
Sınıfın tam hali şöyledir
...
@SpringApplicationConfiguration(classes = { Config.class })
@RunWith(SpringJUnit4ClassRunner.class)
public class JUnitTest {
// katman [UI]
@Autowired
@Qualifier("ui1")
private IUi ui1;
@Autowired
@Qualifier("ui2")
private IUi ui2;
// katman [métier]
@Autowired
@Qualifier("metier1")
private IMetier metier1;
@Autowired
@Qualifier("metier2")
private IMetier metier2;
// katman [dao]
@Autowired
@Qualifier("dao1")
private IDao dao1;
@Autowired
@Qualifier("dao2")
private IDao dao2;
@Test
public void testDao() {
Assert.assertEquals(30, dao1.doSomethingInDaoLayer(10, 20));
Assert.assertEquals(-10, dao2.doSomethingInDaoLayer(10, 20));
}
@Test
public void testMetier() {
Assert.assertEquals(32, metier1.doSomethingInMetierLayer(10, 20));
Assert.assertEquals(-12, metier2.doSomethingInMetierLayer(10, 20));
}
@Test
public void testUI() {
Assert.assertEquals(34, ui1.doSomethingInUiLayer(10, 20));
Assert.assertEquals(-14, ui2.doSomethingInUiLayer(10, 20));
}
}
- 8-10. satırlar: (9. satırda adı belirtilen) [ui1] adlı bean enjekte edilir (8. satır). 10. satırda, bir sınıf örneği değil, bir arayüz örneği enjekte edildiğine dikkat edilmelidir;
- 21-32. satırlar: [Config] sınıfında tanımlanan diğer bean'ler de aynı şekilde enjekte edilir;
- satır 34: [@Test] anotasyonu, testler sırasında çalıştırılacak bir yöntemi belirtir. Diğer olası anotasyonlar şunlardır:
- [@BeforeClass]: testlere başlamadan önce çalıştırılacak yöntem;
- [@AfterClass]: tüm testler tamamlandıktan sonra çalıştırılacak yöntem;
- [@Before]: her testten önce çalıştırılacak yöntem;
- [@After]: her testten sonra çalıştırılacak yöntem;
- 36. satır: [dao1.doSomethingInDaoLayer(10, 20)] çağrısının gerçekten 30 değerini döndürdüğü kontrol edilir. İlk parametre geleneksel olarak beklenen değer, ikincisi ise gerçek değerdir;
- satır 36: [IDao] arayüzünün [dao1] örneğini test eder;
- satır 37: [IDao] arayüzünün [dao2] örneğini test eder;
- 42. satır: [IMetier] arayüzünün [metier1] örneğini test eder;
- 43. satır: [IMetier] arayüzünün [metier2] örneğini test eder;
- 48. satır: [IUi] arayüzünün [ui1] örneğini test eder;
- satır 36: [IUi] arayüzünün [ui2] örneğini test eder;
Bir test yönteminde kullanılabilecek doğrulama ifadeleri şunlardır:
- assertEquals(ifade1, ifade2): iki ifadenin değerlerinin eşit olup olmadığını kontrol eder. Birçok ifade türü kabul edilir (int, String, float, double, boolean, char, short). İki ifade eşit değilse, [AssertionFailedError ] türünde bir istisna atılır,
- assertEquals(reel1, reel2, delta): iki reel sayının delta kadar farkla eşit olup olmadığını kontrol eder; c.a.d abs(reel1-reel2)<=delta. Örneğin, iki değerin 10⁻⁶'ya yakın olup olmadığını kontrol etmek için assertEquals(reel1, reel2, 1E-6) yazılabilir,
- assertEquals(message, expression1, expression2) ve assertEquals(message, réel1, réel2, delta), [assertEquals] yöntemi başarısız olduğunda atılan [AssertionFailedError] türündeki istisnaya eşleştirilecek hata mesajını belirtmeye olanak tanıyan varyantlardır;
- assertNotNull(Object) ve assertNotNull(message, Object): Object referansının null'a eşit olmadığını doğrular,
- assertNull(Object) ve assertNull(message, Object): Object referansının null olup olmadığını kontrol eder,
- assertSame(Object1, Object2) ve assertSame(message, Object1, Object2): Object1 ve Object2 referanslarının aynı nesneye işaret edip etmediğini kontrol eder,
- assertNotSame(Object1, Object2) ve assertNotSame(message, Object1, Object2): Object1 ve Object2 referanslarının aynı nesneye işaret etmediğini kontrol eder;
Testi yürütmek için aşağıdaki adımları izleyebilirsiniz:
![]() |
Aşağıdaki sonuç elde edilir:
![]() |
Burada tüm testler başarılı olmuştur. Peki bu örnek neyi göstermektedir? Spring çerçevesinin katmanlı bir mimarinin yapılandırılmasında sağladığı esnekliği göstermektedir. Yalnızca yapılandırma yoluyla [Ui1, Metier1, Dao1] veya [Ui2, Metier2, Dao2] uygulamasını kullanmaya karar verilebilir. Dolayısıyla, önceki JUnit testinde, yalnızca [ui1, metier1, dao1] bean'lerinin enjeksiyonunu korursak, 1. mimariyle çalışmış oluruz. Mimariyi değiştirmek için, enjekte edilen bean'leri değiştirmek yeterlidir. Bu, arayüzleri uygulayan katmanların kodunda herhangi bir değişiklik yapılmasına gerek kalmadan gerçekleştirilir. Bu tür programlamaya “arayüzlerle programlama” denir; çünkü katmanları uygulayan sınıfların örnekleri değil, arayüzlerinin örnekleri kullanılır.
2.6. Conclusion
- Spring, singleton (tek örnek) olan nesneleri yönetir. Spring ayrıca, Spring'den bir örnek talep edildiğinde her seferinde örneklendirilen nesneleri de yönetir. Bu durum da bu belgede ele alınacaktır;
- bu nesneler, birbiriyle birleştirilebilen çeşitli şekillerde tanımlanabilir:
- bir XML dosyasında,
- [@Configuration] ile anotlanmış bir Java sınıfında,
- [@Component, @Service, ...] anotasyonuyla işaretlenmiş herhangi bir Java sınıfında;
- bir Spring nesnesi, [@Autowired] anotasyonu ile başka bir Spring nesnesine enjekte edilebilir. Buna bağımlılık enjeksiyonu (DI: Dependency Injection) denir;
- Spring, arayüz tabanlı programlama paradigmasıyla birlikte kullanıldığında katmanlı mimarileri yapılandırmak için oldukça kullanışlıdır;




















































