# Spring Framework
Spring Framework, birçok yazılım kütüphanesinin bir araya gelmesiyle ortaya çıkmıŠyazılım geliÅtirme platformudur. Spring Core (çekirdek) kütüphanesi en temel yapısıdır. Spring Core olmadan diÄer Spring Framework kütüphaneleri de çalıÅmayacaktır.
Bu nedenle çekirdek kütüphaneyi proje dahil ederek diÄer kütüphaneleri dilediÄiniz gibi de seçebilirsiniz. ÃrneÄin, Hibernate, JSF, JSP, Struts gibi birçok Java teknolojisiyle birlikte çalıÅtırılabilir bir alt yapıdır.
Javaânın gücü topluluklarından gelmektedir. Spring Framework Java Communityâlerden (topluluk) bir tanesidir. 2003 yılında ortaya çıkmıÅtır. Amacı yazılımcıların JavaEE (Java Enterprise Edition) projelerini daha kolay ve verimli bir Åekilde geliÅtirmesini saÄlamaktır.
Spring Frameworkâün 3 tane önemli özelliÄi bulunmaktadır.
- Inversion Of Control
- Dependency Injection
- Aspect Oriented Programming
**Inversion Of Control**
Yazılımlarda sınıfları dizayn edip gerçek hayattaki nesneleri modellemeye çalıÅırız. Ardından, programımız çalıÅmaya baÅladıÄında tasarladıÄımız bu sınıflardan nesneler üretmeye baÅlarız. Nesnelerin birbirine ihtiyaçları olur. Bu kaçınılmaz bir durumdur.
Tüm yazılımlarda sınıflar ihtiyaç duydukları ek özellikleri veya nitelikleri Inheritance (Kalıtım) yoluyla veya Aggregation (sınıf içinde bir nesne referansı tutarak) yoluyla bünyelerine dahil ederler. Böylece ihtiyaç duydukları fonksiyonları veya deÄiÅkenleri kullanabilirler.
Nesneler arası bu baÄımlılıklar ve dolayısıyla bu nesnelerin yaÅam döngüsü yazılımcı sorumluluÄundadır. Nesnenin yaÅam döngüsünden kastımızda nesneleri yazılımcıların yazdıÄı programlar üretirler, nesnelerin hafızadan temizlenmesi iÅi ise Garbage Collector (Ãöp Toplayıcı) sistemine aittir.
Bu hafıza temizleme mekanizması Javaânın yazılımcılara sunduÄu bir alt yapıdır. Böylece, yazılımcılar nesneleri hafızadan temizlemekle uÄraÅmazlar ve hafıza yönetimini Javaânın sorumluluÄuna bırakırlar.
İÅte nesneler arası bu baÄımlılıkların ve nesnelerin yaÅam döngüsünün sorumluluÄunun yazılımsal bir frameworkâe teslim edilmesine Inversion Of Control denir. Spring Framework bu sorumluluÄu yazılımcıdan alıp kendisi üstlenir.
GerektiÄinde Spring Framework devreye girip yapması gerekenleri yaptıktan sonra kodun akıÅını tekrar yazılımcının koduna teslim eder. Bu mekanizma Spring Frameworkâün yer aldıÄı projelerde program çalıÅtıÄı süre boyunca defalarca kez tekrarlanabilir.
**Dependency Injection/Inversion**
Yazılım projelerinde nesneler arası baÄımlılıklardan kaçınmanın mümkün olmadıÄından bahsettik. Ãünkü, bu nesneler bir araya gelerek yazılımın çalıÅmasını saÄlarlar. O nedenle bu baÄımlılık ne Åekilde yönetileceÄi önemli bir konudur.
ıkı baÄlarla bir araya gelmiÅ nesnelerle oluÅturulan yazılımların kırılganlıÄı ve kod bakım maliyeti yüksektir. Bir hatayı düzeltirken baÅka bir kod parçasının çalıÅmaz hale gelmesi kaçınılmaz olabilir. O nedenle SOLID Prensiplere, Nesneye Dayalı Programlama ilkelerine uygun kod yazmak yazılım bakım düÅürdüÄü gibi kaliteli bir yazılım projesinin oluÅmasına olanak verir. Bu noktada Tasarım Desenleri de elimizi güçlendirir.
Nesneler arası baÄımlılık konusuna dönecek olursak temel prensibimiz nesneler arasında gevÅek baÄlı (Loosely Coupled) iliÅkiler oluÅturmaktır. Tabi bunun sözel bir Åekilde ifade edilmesi çok büyük bir anlam uyandırmayabilir. O nedenle bir örnek vererek açıklamaya çalıÅalım. Diyelim ki bir e-ticaret sitesinde alıÅveriÅ sepetinin toplam ücretini hesaplayıp ödeme yapabilen PaymentService isminde bir sınıfımız olsun.
Bu sınıf toplam ücreti bir ödeme sistemi vasıtasıyla gerçekleÅtirsin. Bu ödeme sistemi de BestFastPay isminde bir ödemesi sistemi olsun. PaymentService sınıfı Aggregation yoluyla BestFastPay isimli nesneye baÄımlılıÄı olduÄunu düÅünelim. Dolayısıyla PaymentService sınıfı içinde BestFastPay sınıfından bir nesnenin deÄiÅken olarak bulunması doÄaldır.
```java
public PaymentService {
private BestFastPay paymentIntegrator;
public PaymentService() {
this.paymentIntegrator = new BestFastPay();
}
public void makePayment() {
this.paymentIntegrator.charge();
}
}
```
Yukarıdaki örnekte görüldüÄü gibi ihtiyaç duyduÄumuz nesne baÄımlılıÄını ânewâ anahtar kelimesi ile oluÅturuyoruz. Böylece PaymentService sınıfı ile BestFastPay ödeme sistemi nesnesi arasında sıkı sıkıya bir baÄ kuruyoruz. Ãünkü, artık PaymentService sınıfı âBestFastPayâ dıÅında baÅka bir tip ödeme sistemi ile çalıÅamayacaktır.
Ancak, kodun içine girip kurucudaki nesnenin tipini deÄiÅtirip yeni ödeme sistemini entegre edebiliriz. Bu durumda Open/Closed prensibe uygun deÄildir. Yazılan kodların deÄiÅime kapalı geniÅlemeye açık olması lazımdır. Bir sınıfın sadece bir sebeple deÄiÅtirilmesi gerekmektedir. İÅte bu sıkı baÄımlılıÄı tersine çevirmek gerekmektedir.
Ayrıca, sınıfın ihtiyaç duyduÄu nesneyi direkt olarak PaymentService içinde oluÅturmaktansa baÄımlılıÄın dıÅarıdan gönderilmesi gerekmektedir (Injection).
İleride ödeme sistemini deÄiÅtirmek istediÄimizde PaymentService sınıfında deÄiÅiklik yapmak gerekecektir.
Kod mimarisini aÅaÄıdaki gibi deÄiÅtirirsek gevÅek baÄlı bir yapı kurmuÅ olacaÄız (Loosely Coupled).
Ãncelikle ödeme sistemlerinin hepsi ödeme yapan bir fonksiyona sahiptir. Bu fonksiyon double tipte bir toplam fiyat bilgisi alır ve ödemeyi gerçekleÅtirir. Ãdemeyi gerçekleÅtirdiÄi algoritma ve yöntem ödeme sistemlerinin hepsinde birbirinden farklı olabilir. Bu nedenle ödeme yapabilme özelliÄini interface olarak soyut bir Åekilde tanımlıyoruz. Ãünkü, bu özellik alt sınıflarda kendi ihtiyaçlarına göre doldurulacaktır.
```java
public interface PaymentIntegrator {
public boolean charge(double totalPrice);
}
```
Sonrasında tüm ödeme sistemleri yukarıdaki interfaceâden kalıtım alacaktır. Böylece ödeme sistemi sınıflarımı soyutlaÅtırarak tek bir interface altında toplayabiliyorum. âBestFastPayâ ve âSuperFastPayâ isminde iki tane ödeme sistemimiz olduÄunu düÅünün.
```java
public BestFastPay implements PaymentIntegrator {
public boolean charge(double totalPrice) {
// make best fast payment ...
}
}
public SuperFastPay implements PaymentIntegrator {
public boolean charge(double totalPrice) {
// make super fast payment ...
}
}
```
En baÅında belirttiÄimiz gibi PaymentService sınıfı alıÅveriÅ sepetini hesaplayıp baÄımlılık yoluyla bünyesinde barındırdıÄı herhangi bir ödeme sistemiyle ödemeyi gerçekleÅtirecektir. İÅte bu noktada ödeme sisteminin ne olduÄundan baÄımsız bir kod parçası yazmalıyız ki ileride ödeme sistemi deÄiÅtiÄinde PaymentService sınıfı bundan etkilenmesin.
Bu noktada elimizde soyutlama gücünü arttıran interfaceâler bulunmaktadır. Zaten bizler de ödeme sistemlerimizi tek bir interface tipinden kalıtım aldırmıÅtık. Böylece, PaymentService sınıfına ödeme sistemlerinden herhangi bir alt sınıfı baÄımlılık olarak vermek yerine direkt olarak interface ile temsil edebiliriz. Böylece PaymentService sınıfı hangi ödeme sistemini tuttuÄundan haberdar olmadan ödemeyi gerçekletirebilir.
```java
public PaymentService {
private PaymentIntegrator paymentIntegrator;
public PaymentService(PaymentIntegrator paymentIntegrator) {
this.paymentIntegrator = paymentIntegrator;
}
public void makePayment() {
this.paymentIntegrator.charge();
}
}
```
Yukarıdaki örnekte de görüldüÄü gibi PaymentService artık interface tipinde bir ödeme entegratör nesnesi tutmaktadır. Ayrıca, ânewâ kelimesi ile direkt bir nesne oluÅturmuyoruz bu baÄımlılıÄın kurucu metot üzerinden dıÅarıdan gönderilmesini saÄlıyoruz. Böylece ileride PaymentService sınıfı BestFastPay ödeme sisteminden SuperFastPay ödeme sistemine geçtiÄinde PaymentService sınıfındaki kodlarımız deÄiÅmeyecektir. Bu yolla Open/Closed prensibi de saÄlamıŠoluyoruz.
İÅte Spring Framework yazılımcıların yönettiÄi bu baÄımlılıkların yönetilmesi sorumluluÄunu kendi üzerine almaktadır. Ve Dependency Injection yöntemiyle ihtiyaç duyulan baÄımlılıÄı Spring devreye girip yazılımcıya kullanıma hazır olacak Åekilde sunmaktadır.
BaÄımlılıÄın da yaÅam döngüsünü kendisi yönetmektedir. Spring Framework de baÄımlılık yönetiminde interfaceâe dayalı bir yol izlenmesini beklemektedir. Interfaceâe dayalı Dependency Injection yukarıdaki gibi soyutluluÄu arttırarak nesneler arası gevÅek baÄların kurulmasına yardımcı olmaktadır.
## **Aspect Oriented Programming (AOP)**
Spring Framework AOPâyi sıkı sıkıya destekler. AOP yöntemiyle yazdıÄımız projenin kodlarında belli noktaları keserek, kestiÄimiz bu kesiÅim olan noktalarda bazı kodların bizim müdahalemiz olmadan otomatik olarak çalıÅtırılmasını isteyebiliriz. Bu kesiÅen noktalarda kodların otomatik çalıÅtırılması iÅi yine Spring Framework ile Aspectâlerin birlikte çalıÅmasıyla saÄlanabilir.
Spring Framework bu programlama yöntemini destekler. ÃrneÄin projenizde tüm fonksiyonların çalıÅma sürelerini ölçmenizi istediklerini düÅünün. Bu durumda her fonksiyon içine girip tek tek çalıÅmasını ölçen kodları yazmak gerekecektir. Fakat, AOPâyi kullanarak bu fonksiyonları iÅaretleyip fonksiyonlar çalıÅtırıldıÄı esnada süre ölçmeyi saÄlayan kodlar otomatik devreye girer ve süre ölçümünü loÄlar.
Bu kodların otomatik olarak devreye alınması ve sonra yine kod akıÅının yazılımcının koduna bırakılmasını Spring ve Aspectâler saÄlar. Böylece, her fonksiyona defalarca aynı kodu yazmaktan bizi kurtarır.
Aspectâleri de yine biz yazılımcılar tasarlarız, hatta aspect hangi iÅleri yapacaÄını da biz kodlarız. Fakat, bu kodun devreye alınıp otomatik olarak çalıÅtırılması ve tekrardan sorumluluÄu yazılımcının koduna devretmesi Spring Framework ile olmaktadır. AOP de Spring Frameworkâün güçlü bir özelliÄidir.
**Spring Ãekirdek Mimarisi**
Spring Framework ile nesne baÄımlılıklarını yönetme iÅini çözüyoruz. Aynı zamanda Spring Framework içinde kurumsal anlamda yazılım geliÅtirmek için birçok kütüphane bulunmaktadır. Veri tabanına eriÅimden, web uygulamaları için gerekli olan kütüphanelere kadar geniÅ bir kütüphane yelpazesi vardır.

## **Spring Core**
Spring Core kütüphanesi çekirdek kütüphanedir. BaÄımlılıkların yönetiminin yapıldıÄı yerdir. İçinde Core ve Beans nesneleri vardır, bu nesne ile yazılımın çalıÅma süresi boyunca Spring yöneteceÄi baÄımlılıkları bu modüllerde yönetir. Spring Frameworkâde Bean olarak tanımlanmıŠsınıflar Context modülünde toplanılır. Yazılım çalıÅma zamanında ihtiyaç duyulan nesne baÄımlılıkları Context üzerinden kullanıma sunulur.
## **Spring Test**
Spring Framework ile JUnit testlerin çalıÅtırılmasını saÄlayan alt yapıdır.
## AOP (Aspect Oriented Programming)
Aspect tanımlayarak kodu belli noktalarda kesen ve ardından kestiÄi bu noktalarda otomatik olarak çeÅitli kodlar çalıÅtırabilen mekanizmayı saÄlar. Yukarıda detayları mevcuttur.
## **Data Access**
Spring Frameworkâün veri tabanı yönetim sistemleriyle etkileÅime geçmek için sunduÄu alt yapıdır. Biliyoruz ki tüm kurumsal projeler verileri veri tabanı sistemlerinde saklamaktadırlar. Dolayısıyla yazdıÄımız projeler illaki veri tabanlarıyla iletiÅim halinde olacaklardır. Springâin bu kütüphaneleri buna olanak tanımaktadırlar. JDBC, ORM Kütüphanelerini kullanımı, Transaction yönetimi gibi sorumlulukları bu kütüphane yerine getirir.
## **Web**
Spring Framework ile web uygulamaları geliÅtirebilmek için gerekli kütüphaneleri saÄlar. Java Web-Servlet, Web-Portlet gibi teknolojilerle çalıÅabilmeyi kapsar.
## **Spring Uygulaması OluÅturmak**
Spring uygulaması oluÅturmak için çeÅitli ayarlar yapılması gerekmektedir. Bu ayarları Annotation (Etiket) tabanlı veya XML tabanlı yapabilirsiniz. Spring ilk çıktıÄı zamanlar XML ile ayalar yapmak yaygındı. Fakat, sonrasında bu daha kolay hale getirildi. Artık, neredeyse tüm konfigrasyon Annotation üzerinden yapılmaktadır.
YazdıÄımız sınıfları Core, Beans altyapılarını kullanarak Springâin Context modülüne eklemeliyiz. Spring Contextâte yer almayan bir sınıf uygulama içinde Spring Framework tarafından nesne baÄımlılıÄı olarak sunulamaz. Bu nedenle çeÅitli tanımlamalar yaparak ilgili sınıfı Spring Contextâe dahil etmek gerekmektedir.
ÃrneÄin Salary isminde maaÅ bilgisini tutan bir sınıfımız olsun. Bu maaÅ bilgilerini de JSON veri formatına çeviren basit sınıf tasarladıÄınızı düÅünün. AÅaÄıda âSalaryJsonConverterâ isimli sınıf bulunmaktadır. Normal bir Java sınıfı tasarladık. Henüz ekstra bir özelliÄi yok ve Spring Contextâe dahil edilmiÅ deÄil.
```java
public class SalaryJsonConverter {
public String convertToJson(Salary salary) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(salary);
}
}
```
Yukarıdaki sınıfı XML yoluyla Spring Contextâe dahil edip Spring tarafından yönetilebilen bir baÄımlılık haline getirmek istiyorsak bir XML dosyası oluÅturup içine Bean olarak tanımlamak gerekecektir.
```java
```
Yukarıdaki gibi âapplicationContext.xmlâ isminde bir dosya tanımladık. Bu Spring Framework için özel bir XML dosyasıdır. Spring Contextâe dahil etmek istediÄimiz sınıfları Bean olarak tanımlayıp kullanabiliriz.
```java
@Component
public class SalaryJsonServiceImpl {
@Autowired
private SalaryJsonConverter jsonConverter;
public String convertToJson(Salary salary) throws JsonProcessingException {
return jsonConverter.convertToJson(salary);
}
}
```
Yukarıda âSalaryJsonConverterâ sınıfından bir nesne baÄımlılık olarak âSalaryJsonServiceImplâ sınıfında Dependency Injection yoluyla eklenmiÅtir. Spring Framework Contextâin de olan bir baÄımlılıÄı kullanmak için â@Autowiredâ anahtar kelimesi kullanılır.
Böylece Spring Framework, Contextâten bu sınıfa ait bir nesneyi burada kullanılabilir bir nesne olarak kullanıma sunar. Dikkat ederseniz ânewâ anahtar kelimesi ile bu baÄımlılıÄı biz oluÅturmuyoruz. Spring âSalaryJsonConverterâ sınıfından bir nesne üretip bizim kullanımımıza sunuyor. BaÄımlılıÄı bizim yerimize kendisi yönetiyor.
Ãzerine düÅen sorumluluÄu yerine getirmek için devreye giriyor, baÄımlılıÄı hazırlayıp bize teslim ediyor. Ardından kodun kontrolünü yazılımcıya tekrardan devrediyor.
XML ile Bean tanımı yapmadan da Spring Contextâe Bean ekleyip baÄımlılık olarak kullanabiliriz. Bunun içinde Annotation (Etiket) tabanlı yöntemi kullanıyoruz.
```java
@Configuration
public class ApplicationConfig {
@Bean
public SalaryJsonConverter getSalaryJsonConverter() {
return new SalaryJsonConverter();
}
}
```
Yukarıdaki örnekte âApplicationConfigâ sınıfı ile XML dosyası yerini tutan ayarlar sınıfını tasarlıyoruz. Spring Framework ile ilgili konfigürasyonları böylelikle etiket (annotation) tabanlı yöntemlerle bu sınıf üzerinde tanımlayabiliriz.
Dikkat ederseniz âSalaryJsonConverterâ isimli sınıfımızı â@Beanâ etiketi ile Spring Contextâe dahil ediyoruz. Böylece, artık Spring tarafından bir nesne baÄımlılıÄı olarak projede kullanılabilecek.
### Spring Bean Annonations (Etiketleri)
Spring Frameworkâde bir Java sınıfını Bean olarak ayarlamak için birden fazla yol bulunmaktadır. XML konfigürasyon tanımıyla ve @Bean etiketiyle (Annotation) Java sınıflarını Spring Bean olarak tanımlayabiliriz. Bu tanımlama biçimini yukarıdaki örneklerde ele almıÅtık. Bu yöntemler dıÅında Spring Frameworkâün Bean tanımlamak için var olan etiketlerini kullanarak da Java sınıflarını Spring Bean olarak tanımlama Åansına sahipsiniz.
Bu etiketler aÅaÄıdaki gibidir:
- @Component
- @Service
- @Repository
- @Controller
- @Configuration
- @Aspect
Spring Frameworkâte ister XML tabanlı konfigürasyon olsun isterse de Etiket (Annotation) tabanlı konfigürasyon olsun her iki yöntemde de Spring Beanâlari tek tek tanımlamak zorunda deÄilsinizdir. Spring Framework belirttiÄiniz Java paketleri (package) altında yer alan sınıfları tarayarak yukarıda bahsettiÄimiz etiketler ile iÅaretlenmiÅ sınıfları Spring Bean olarak Spring Context içine dahil edebilir.
Artık Spring dünyasında etiket tabanlı ayarlama yaygın olduÄu için ve bu yöntemin daha kolay, verimli olmasından dolayı Spring konfigürasyonlarınızı etiket tabanlı yöntemle yapmanız daha uygun olacaktır.
@ComponentScan etiketi ile bir veya birden fazla Java package altında bulunan @Component, @Service, @Repository, @Controller, @Configuration, @Aspect etiketlerinden birine sahip sınıfları tarayıp Spring Contextâe dahil edebiliyoruz.
AÅaÄıda Spring Framework bulunan bir projedeki etiket tabanlı konfigürasyonu görüyorsunuz.
```java
@Configuration
@ComponentScan(basePackages = {
"com.spring.basics.dao.impl",
"com.spring.basics.console",
"com.spring.basics.service.impl",
"com.spring.basics.aspect"})
public class ApplicationConfig {
}
```
@ComponentScan ile yukarıda 4 tane Java package Spring Framework taranacak ve sınıflar Spring Contextâe dahil edilecektir.
## **@Componet Etiketi**
Bu etiket sınıf tanımı üstünde kullanılabilir. Yukarıda @ComponentScan ile Spring Frameworkâün paketleri taradıÄından bahsetmiÅtik. EÄer ki taradıÄı sınıflar içinden @Component etiketiyle iÅaretlenmiÅ bir sınıf görürse bunu Spring Contextâe dahil ediyor. Böylece, Spring Contextâe dahil ettiÄi sınıfları yazılım geliÅtirirken bir nesne baÄımlılıÄı olarak kullanabiliyoruz. Biliyorsunuz ki, @Autowired etiketi ile bir nesne baÄımlılıÄı ilgili sınıfa inject edilebilir. Buna Dependency Injection diyoruz.
```java
@Component
public class EmployeeSelectService {
// Java codes
}
```
## **@Repository Etiketi**
DAO veya Repository sınıfları veri tabanıyla etkileÅim içinde olan sınıflardır. Bu nedenle bu veri eriÅimi saÄlayan sınıflarda @Repository etiketi kullanabiliriz. Aynı Åekilde bu katmandaki sınıflarda @Component etiketi kullanabilirdik.
Hibernate gibi ORM kütüphanesini Spring ile kullandıÄımızda, @Repository etiketi ile iÅaertlenmiÅ bu DAO sınıflarında oluÅan hatalar otomatik olarak Springâin DataAccessExceptionâlarına dönüÅtürülebilir. Böylece hataya iliÅkin daha detaylı bilgi edinmiÅ oluruz.
```java
@Repository("employeeModificationDraftDAOImpl")
public class EmployeeModificationDAO {
// Java codes
}
```
## **@Service Etiketi**
DAO katmanı ile veriye eriÅim saÄlıyorduk. Service katmanı ise iÅ mantıÄını kodladıÄımız katmandır. Burada iÅ akıÅları yer alır. Mesela bir e-ticaret sitesinde ödeme akıÅı Service katmanında kodlanır. Ya da bankacılık uygulamasında para transferi akıÅı yine Service katmanında kodlanır. Bu sınıfları etiketlemek için @Service etiketi kullanılabilir. Aynı Åekilde bu katmandaki sınıflarda @Component etiketi kullanabilirdik.
```java
@Service
public class EmployeeSelectService {
// Java codes
}
```
## **@Controller**
Bu etiket daha çok web katmanı için kullanılır. ÃrneÄin Spring MVC kütüphanesi ile REST katmanı yazdıÄımızı düÅünelim. Bu durumda REST servisi için tasarladıÄımız sınıfları @Controller etiketi ile ifade edebiliriz.
```java
@Controller
public class VehicleController {
// Java codes
}
```
## **@Configuration Etiketi**
Spring Framework ile ilgili konfigürasyonları etiket tabanlı yapabileceÄinizden bahsetmiÅtik. Java tarafında bu konfigürasyon sınıflarını tanımlamak için @Configuration etiketi kullanılır. Böylece, Spring Framework bu sınıfın bir konfigürasyon sınıfı olduÄunu anlar. Biliyorsunuz ki konfigürasyon sınıflarında Bean tanımları yapılabilir. Aynı Åekilde hangi Java paketleri altında tarama yapılacaÄı belirtilerek Spring Contextâe Spring Beanâleri otomatik olarak eklenir.
```java
@Configuration
@ComponentScan(basePackages = {
"com.spring.basics.dao.impl",
"com.spring.basics.console",
"com.spring.basics.service.impl",
"com.spring.basics.aspect"})
public class ApplicationConfig {
@Bean
public EmployeeModificationService getEmployeeModificationService() {
return new EmployeeModificationServiceImpl();
}
}
```
Yukarıdaki örnekte 4 Java paketini tarayıp Bean olabilecek sınıfları Spring Contextâe ekliyoruz. Yukarıda saydıÄımız Bean etiketlerinden herhangi birini sınıf tanımında bulunduran sınıf Spring Contextâe dahil edilir. Aynı zamanda konfigürasyon sınıfımızda âEmployeeModificationServiceâ tipinden bir sınıfı Bean olarak Spring Contextâe dahil ediyorum. @Bean etiketiyle belirttiÄimiz nesne artık Spring Contextâte kullanabileceÄimiz bir dependency (baÄımlılık) olarak eklenmiÅ durumdadır.
## **@Aspect Etiketi**
Spring, AOP yöntemini destekleyen bir frameworkâtür. Spring projesinde bir Aspect sınıfı tanımlamak istiyorsak @Aspect etiketini kullanmalıyız.
```java
@Aspect
@Component
public class MethodRunningTimeAspect {
// Java codes
}
```
#### Spring Bean Scopes (Kapsam)
Spring Bean Scope kavramı Spring Contextâe dahil ettiÄimiz nesnelerin yaÅam süresini (Contextâten eriÅim biçimini) ve döngüsünü ifade eder.
- singleton
- prototype
- session
- application
- request
Yukarıda belirtilen Spring Bean Scope belirteçleri vardır. Bu belirteçlerin her biri Spring Contextâte yer alan nesnelerin ne Åekilde üretilip kullanılabileceÄini belirtir.
Kapsamlar @Scope etiketi ile belirtilir. Hemen Spring Bean etiketi altında yer alır.
âsingletonâ Scope
âsingletonâ olarak belirtilmiÅ bir nesne baÄımlılıÄı Spring Context içinde tekil bir nesne olarak tutulur. Bu nesne örneÄine ihtiyaç duyan herkese aynı nesne referansı verilir. Yani, Spring Contextâte ilgili sınıftan üretilmiÅ sadece bir nesne tutulur. Dolayısıyla yazılımı geliÅtirirken bu nesneye baÄımlılık duyup @Autowired ile inject ettiÄimiz her noktada Spring Context bize aynı nesneyi verecektir.
```java
@Service
@Scope(value = "singleton")
public class EmployeeSelectService {
// Java codes
}
```
âprototypeâ Scope
âprototypeâ olarak belirtilmiÅ sınıflarda ise Dependency Inject ile (@Autowired ile) nesne baÄımlılıÄı eklediÄimiz her noktada Spring Context ilgili sınıfa ait yeni bir nesne üretip verecektir. Yani her @Autowired çaÄrımızda yeni bir nesne almıŠolacaÄız.
```java
@Service
@Scope(value = "prototype")
public class EmployeeModificationService {
// Java codes
}
```
Yukarıda bahsettiÄimiz âsingletonâ ve âprototypeâ kapsamları her tip Spring projesinde kullanılabilir. Fakat, âsessionâ, ârequestâ ve âapplicationâ kapsamları sadece web projelerinde kullanılabilir.
ârequestâ Scope
ârequestâ scope olarak tanımlanmıŠbir sınıf için Spring Contextâten bir nesne baÄımlılıÄı talep edildiÄinde her http isteÄine karÅılık yeni bir nesne örneÄi oluÅturur. âprototypeâ gibidir. ârequestâ scope olarak iÅaretlenmiÅ bir sınıfı proxy (temsili) bir örneÄi oluÅturulur. Bunun sebebi Bean oluÅturulurken henüz ortada bir http isteÄi yoktur. Bu nedenle proxy nesne oluÅturulur.
```java
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator requestScopedBean() {
return new HelloMessageGenerator();
}
```
âsessionâ Scope
âsessionâ scope olarak belirtilmiÅ bir sınıfın nesne örneÄi HTTP Session oluÅtuÄunda yaratılır. Session boyunca da kullanılır.
```java
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator sessionScopedBean() {
return new HelloMessageGenerator();
}
```
âapplicationâ Scope
Web uygulaması yaÅamına devam ettiÄi sürece âapplicationâ scope olarak oluÅturulmuÅ nesneler tek bir nesne örneÄi oluÅturulmuÅ Åekilde kullanılacaktır. Yani burada web uygulamasının yaÅam süresi ServletContextâin yaÅam süresine baÄlıdır. Aynı ServletContextâi paylaÅan birden çok web uygulaması da yine âapplicationâ scope olarak belirtilmiÅ singleton (tekil) nesne örneÄini kullanabilecektir. Bu özelliÄiyle âapplicationâ scope âsingletonâ scopeâdan ayrılır. âsingletonâ scope sadece ilgili uygulamanın yaÅam süresi boyunca tekillik saÄlar.
```java
@Bean
@Scope(
value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator applicationScopedBean() {
return new HelloMessageGenerator();
}
```
##### Spring Boot
Spring Boot, Spring Framework ailesinin bir alt modülüdür. Spring Boot ile yazılımcıların hızlı geliÅtirme yapabilmesi saÄlanmaya çalıÅılmıÅtır. Gerçekten çok hızlı bir Åekilde diÄer gereksiz detaylara takılmadan sıfırdan bir web uygulaması geliÅtirmek çok basittir.
Spring Boot, yazılımcıların yeni nesil geliÅtirme aracıdır. Ãzellikle âstarterâ isimli baÄımlılıklara (dependency) dayalıdır. Buradaki baÄımlılıktan kastettiÄimiz Maven veya Gradle gibi baÄımlılıkların yönetildiÄi alt yapılarda kullandıklarımızdır.
Ãzetle, ihtiyacımız olan Java kütüphanelerini ifade eder. Biliyoruz ki Maven ve Gradle bu kütüphane baÄımlılıÄını yönetmek için geliÅtirilmiÅ alt yapılardır. âstarterâ baÄımlılıkları birbiriyle uyumlu versiyonda olan tüm kütüphaneleri bir araya getirmiÅtir.
ÃrneÄin Maven projenizde aÅaÄıdaki gibi web geliÅtirme yapabilmek için bir starter baÄımlılıÄı eklediÄinizde web için ihtiyacınız olan tüm kütüphaneler eklenecektir. Eklenen bu kütüphaneler topluluÄu birbiriyle en uyumlu Åekilde çalıÅan versiyonlardan oluÅacaktır. Böylece hangi kütüphane hangi versiyon ile uyumluydu diye ayrıca efor harcayıp uÄraÅmayacaksınız.
```java
org.springframework.boot
spring-boot-starter-web
```
Spring Boot projeleri web uygulaması olarak tasarlansa bile âjarâ uzantılı çalıÅtırılabilir bir çıktı üretir. Spring Boot içinde gömülü olarak bir web uygulama sunucusu taÅıdıÄı için bu âjarâ uzantılı çalıÅtırılabilir dosyalar web uygulaması olarak çalıÅabilir. Bu gömülü web uygulama sunucusu Tomcat vb araçlardır.
Klasik yöntemde Java web uygulamaları âwarâ uzantılı dosyalar olarak üretilir. Spring Boot bu açıdan da farklıdır. âjarâ olarak web uygulaması üretilmesi komut satırından çalıÅtırılabilen web uygulamaları anlamına gelmektedir. Bu yönüyle microservices mimarisi için de uygundur.
## **Spring Boot Otomatik Konfigürasyon**
BildiÄimiz üzere Spring Framework ile proje geliÅtirmek için XML tabanlı bir yöntemle veya etiket (Annotation) tabanlı bir yöntemle konfigürasyonlar yapmak gerekiyordu. Spring Boot ile artık siz hiçbir konfigürasyon tanımlamasanız bile Spring Boot kendisi classpathleri, Java packageâları otomatik olarak tarayıp gereken en iyi konfigürasyon kendisi arka planda oluÅturma yeteneÄine sahiptir. Böylece, biz yazılımcılar bir konfigürasyon yapmasak bile Spring Boot uygulamaları varsayılan bir konfigürasyon ile kendisi ayaÄa kalkabilmektedir.
@EnableAutoConfiguration etiketi ile bu özelliÄi aktif hale getirebilirsiniz.
## **Gömülü Web Uygulama Sunucusu DesteÄi**
Spring Boot ile gömülü web uygulama sunucusu desteÄi gelmektedir. Spring Boot uygulamaları bilindiÄi üzere âjarâ uzantılı çalıÅtırılabilir dosyalar vermektedirler. Bu âjarâ dosyası içinde gömülü bir web uygulama sunucusu ile oluÅturulur. ÃrneÄin içinde gömülü bir Tomcat bulunur. âjarâ uygulaması çalıÅtırıldıÄında Tomcat ayaÄa kalkıp web uygulamasını kendi bünyesinde çalıÅtırmaya baÅlar. Böylece bir web uygulama sunucusu bulma derdi ortadan kalkar.
Varsayılan olarak Tomcat web uygulama sunucusu olarak gömülü gelir. Fakat, bunu deÄiÅtirme Åansımız vardır. ÃrneÄin aÅaÄıdaki örnekte Tomcat yerine Jetty web uygulama sunucusu eklenmiÅtir.
```java
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-tomcat
org.springframework.boot
spring-boot-starter-jetty
```
ââ XML etiketleri arasında yer alan ifadeyle âspring-boot-starter-webâ baÄımlılıÄı içinden Tomcat web uygulama sunucusu çıkartılmıÅtır. AÅaÄıda onun yerine âspring-boot-starter-jettyâ baÄımlılıÄı eklenerek varsayılan web uygulama sunucusu deÄiÅtirilmiÅti.
##### Spring Boot Application
Yukarıda Spring Boot ile temel özelliklerden bahsettik. Bir Spring Boot projesini Maven ve Gradle ile bir Java projesi açıp oluÅturabilirsiniz. Spring Boot ile ilgili âstarterâ kütüphaneleri ekleyebilirsiniz. Tüm bunların ardından uygulamanızın Spring Boot projesi olduÄunu belirtmek için bir hamle daha yapmanız gerekmektedir. @SpringBootApplication etiketiyle bir sınıf oluÅturup tanımlama yapmak gerekmektedir.
@SpringBootApplication etiketi tanımlayarak @Configuration, @EnableAutoConfiguration ve @ComponentScan etiketlerini bir arada tanımlamıŠgibi olursunuz. Bu üçünün de iÅlevini yerine getirir.
Spring Boot uygulaması ayaÄa kalkarken tüm paketleri ve classpathâleri tarayarak oluÅturması gereken Beanâleri, baÄımlılıkları ve konfigürasyonları Spring Contextâe ekleyerek çalıÅmaya baÅlar. Spring Boot uygulamasının çalıÅabilmesi için @SpringBootApplication olarak iÅaretlediÄimiz sınıfın içinde âstatic void mainâ isminde bir fonksiyon olmalıdır. Spring Boot uygulamaları bu fonksiyondan itibaren çalıÅmaya baÅlarlar.
```java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
Yukarıda örnek bir Spring Boot Application sınıfı verilmiÅtir.
Spring Boot uygulamalarında çeÅitli konfigürasyon bilgilerini âapplication.propertiesâ isimli özel bir dosyada saklayabilirsiniz. Spring Boot bu özel dosyayı okuyup gerekli ayarlamaları yapmaktadır. Bu dosya genelde âsrc/main/resourcesâ gibi bir Resource dosyasında bulunur.
### Server port ####
server.port=8080
Yukarıdaki örnekte âapplication.propertiesâ dosyasında web uygulama sunucusunun, ki örneÄimizde Tomcat sunucusunun port numarası belirtilmiÅtir. Spring Boot uygulaması âlocalhostâ üzerinden 8080 nolu portta hizmet vermeye baÅlayacaktır.
**Spring Boot Avantajları**
- BaÄlılıklardaki ve kütüphanelerdeki versiyon uyumsuzluklarının önüne geçmektedir.
- Classloaderâın çalıÅma süresini minimize eder. Hızlı bir Åekilde uygulamanın ayaÄa kalkmasını saÄlar.
- âstarterâ baÄımlılıklarla ve otomatik konfigürasyon seçenekleriyle hızlı geliÅtirme yapmayı saÄlar. XML tabanlı konfigürasyonun getirdiÄi zorlukları ve hantallıÄı azaltır.
- Gömülü basit bir web uygulama sunucusu barındırır. Tomcat veya Jetty gibi.
- Eclipse ve IntelliJ gibi IDE ile mükemmel bir entegrasyonu vardır.
**Eclipse üzerinden Spring Boot Projesi OluÅturmak**
Eclipse üzerinden âNew Projectâ diyerek yeni bir Maven projesi oluÅturulur.

âCreate a simple projectâ seçeneÄi seçilerek devam edilir.

Projenin Group Id ve Artifact Id alanları doldurulur. âPackagingâ tipi âjarâ olarak bırakılır.

Projede âcom.spring.basicsâ isminde bir Java package oluÅturulur.
Ardından âpom.xmlâ dosyasına gidip Spring Boot ile ilgili ayarlamalar yapılır.
İlk önce âpom.xmlâ dosyasına âspring-boot-starter-parentâ baÄımlılıÄı eklenir. Bu ana baÄımlılık diÄer eklentileri ve baÄımlılıkları yönetmek için vardır. Kısacası projenin ana modülüdür. Nasıl ki normal maven projelerinde ana (parent) modül baÄlayabiliyorduk. Spring Boot için de ana modülümüz âspring-boot-starter-parentâ olacaktır.
Ardından gerekli âstarterâ baÄımlılıklarımızı ekleyeceÄiz ve son olarak âspring-boot-maven-pluginâ eklentisini âpom.xmlâ dosyamıza tanımlayacaÄız. Bu eklenti ile Spring Boot uygulamalarımızı âjarâ uzantılı dosyalar Åeklinde paketleyebileceÄiz. Ãrnek âpom.xmlâ aÅaÄıdaki gibidir.
```java
4.0.0
chapter6-spring-basics
chapter6-spring-basics
0.0.1-SNAPSHOT
org.springframework.boot
spring-boot-starter-parent
2.1.6.RELEASE
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-aop
chapter6-spring-basics
org.springframework.boot
spring-boot-maven-plugin
```
âspring-boot-starterâ, âspring-boot-starter-webâ ve âspring-boot-starter-aopâ baÄımlılıklarını projemize ekliyoruz. YapacaÄımız uygulama henüz veri tabanına baÄlanmayacaktır. Spring Beanâlerin kullanımı ve Dependency Injection örnekleri yer alacaktır. Scopeâlar ile ilgili örnekler verilecektir.
Son olarak da projemizdeki tüm fonksiyonların ne kadar süre çalıÅtıÄını ölçen bir Aspect tasarlayacaÄız.
âcom.spring.basicsâ paketi altına âApplicationâ isminde bir sınıf oluÅturalım. Bu sınıfımız Spring Boot Application sınıfı olacaktır.
```java
@SpringBootApplication
public class Application {
@MethodRunningTime(active = false)
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
Spring Boot ile ilgili çeÅitli ayarların tutalacaÄı sabit bir dosya tanımlayacaÄız. âapplication.propertiesâ isimli bu dosyayı âsrc/main/resourcesâ altında oluÅturuyoruz.
server.port=7006
Åimdilik sadece Tomcat web uygulama sunucusunun hizmet vereceÄi port bilgisini 7006 olarak belirttik. Bu haliyle uygulamamız çalıÅtırılmaya hazır.

YapacaÄımız örnekte veri tabanına eriÅim saÄlayan bir DAO katmanı olduÄunu hayal edelim. Fakat, ilgili DAO katmanı Åu an sadece veri tabanına baÄlı olarak çalıÅmayacaktır. Veri tabanına baÄlanıyormuÅ gibi düÅüneceÄiz. Hibernate konusundan sonra Springâe ile Hibernate kütüphanesini entegre edeceÄiz. O bölümde veri tabanına baÄlanan bir DAO katmanımız olacaktır.
Ardından, DAO katmanı ile haberleÅen ve iÅ mantıÄını (Business Logic) kodladıÄımız katmanı yazacaÄız. Bu katmanda Service sınıflarımız olacaktır.
Yukarıdaki iki katmanı hazırladıktan sonra Spring üzerinden bir Java konsol uygulaması hazırlayacaÄız.
Böylece bu bölümde Dependency Injection, Spring Bean Annotations (Etiketleri) ve Spring Bean Scopeâları bir arada tek bir örnekte kullanacaÄız.
## **DAO Katmanı**
Ãnceki adımlarda hazırladıÄımız âspring-boot-basicsâ isimli Spring Boot projesine âcom.spring.basics.daoâ isminde bir Java package oluÅturuyoruz. HazırlayacaÄımız DAO sınıflarının kullanacaÄı interfaceâleri tasarlıyoruz. Biliyoruz ki Spring Frameworkâte Dependency Injection yöntemiyle bir nesne baÄımlılıÄını kullanmak istediÄimizde interfaceâden kalıtım almıŠalt sınıf tiplerinden birini tercih etmiyorduk. Onun yerine referans tipini interface tipi olarak vermeyi amaçlıyorduk.
```java
public interface EmployeeModificationDAO {
public boolean save(String record);
public boolean update(String record, Long id);
public boolean delete(Long id);
}
public interface EmployeeSelectDAO {
public List getAll();
public String findById(Long id);
}
```
ÃalıÅan veri tabanına baÄlanıp çalıÅan tablosuyla etkileÅimde olan DAO katmanımız olduÄunu düÅünürsek, veriyi sorgulayacak ve veri üzerinde iÅlem yapacak fonksiyonları barındıran iki tane interface tasarladık. âEmployeeModificationDAOâ isimli interfaceâde tablo üzerinde kayıt eklemek, çıkarmak ve güncellemek için gerekli olan fonskiyonlar tanımlanmıÅtır.
âEmployeeSelectDAOâ isimli sınıfta ise çalıÅan tablosu üzerinde sorgu iÅlemleri yapabilecek interface tasarlanmıÅtır.
âcom.spring.basics.dao.implâ Java paketini oluÅturup yukarıda tanımladıÄımız DAO interfaceâlerden kalıtım alan alt sınıfları oluÅturacaÄız.
```java
@Repository("employeeSelectDAOImpl")
public class EmployeeSelectDAOImpl implements EmployeeSelectDAO {
@Override
public List getAll() {
return Arrays.asList("Ali", "Mehmet", "AyÅe", "Fatma");
}
@Override
public String findById(Long id) {
System.out.println(id + " found!");
return String.valueOf(id);
}
}
@Repository("employeeModificationDAOImpl")
public class EmployeeModificationDAOImpl implements EmployeeModificationDAO {
@Override
public boolean save(String record) {
System.out.println(record + " saved!");
return true;
}
@Override
public boolean update(String record, Long id) {
System.out.println(record + " updated!");
return true;
}
@Override
public boolean delete(Long id) {
System.out.println(id + " record deleted!");
return false;
}
}
```
Alt sınıfları tanımladık. Dikkat edilirse bu sınıfları Spring Contextâe dahil edilip, Spring Framework üzerinden kullanılabilen baÄımlılıklar haline getirebilmek için @Repository etiketiyle iÅaretledik. İleriki adımlarda bu sınıfların dahil edilebilmesi için Spring konfigürasyon sınıfı tasarlayacaÄız.
Bu konfigürasyon sınıfında Spring Frameworkâün hangi paketleri taraması gerektiÄini belirteceÄiz. Böylece @Repository olarak iÅaretlediÄimiz sınıflar Spring Contextâe dahil olmuÅ olacaktır.
@Repository(âemployeeSelectDAOImplâ) tanımlamasıyla çift tırnaklar arasında oluÅacak Spring Beanâe bir isim veriyoruz. Bu isim belirleme konusu yazılımcının isteÄine baÄlıdır. DilediÄiniz ismi verebilirsiniz.
**Service Katmanı**
Temsili de olsa artık bir DAO katmanımız mevcut hale geldi. Åimdi iÅ mantıÄını kodladıÄımız Service katmanı hazırlayacaÄız. Service katmanı hem Java konsol katmanı ile hem de DAO katmanı ile konuÅacaktır. Burada Sunum katmanı olarak Java konsol uygulamasını kullanıyor olacaÄız.
âcom.spring.basics.serviceâ isminde Service katmanındaki sınıflara kalıtım verecek olan interfaceâleri tasarlıyoruz.
```java
public interface EmployeeModificationService {
public boolean save(String record);
public boolean update(String record, Long id);
public boolean delete(Long id);
}
public interface EmployeeSelectService {
public List getAll();
public String findById(Long id);
}
```
âcom.spring.basics.service.implâ paketini oluÅturup yukarıda tanımladıÄımız interfaceâlerden kalıtım alacak olan alt sınıfları oluÅturuyoruz.
```java
@Service
@Scope(value = "singleton")
public class EmployeeSelectServiceImpl implements EmployeeSelectService {
@Autowired
private EmployeeSelectDAO employeeDAO;
@Override
public List getAll() {
return employeeDAO.getAll();
}
@Override
public String findById(Long id) {
return employeeDAO.findById(id);
}
}
@Service
@Scope(value = "prototype")
public class EmployeeModificationServiceImpl implements EmployeeModificationService {
@Autowired
private EmployeeModificationDAO employeeModificationDAO;
@Override
public boolean save(String record) {
return employeeModificationDAO.save(record);
}
@Override
public boolean update(String record, Long id) {
return employeeModificationDAO.update(record, id);
}
@Override
public boolean delete(Long id) {
return employeeModificationDAO.delete(id);
}
}
```
TanımladıÄımız sınıfların en üstüne @Service etiketini ekleyerek bu sınıfları Spring Contextâe dahil edilebilir diye Åekilde iÅaretliyoruz.
Ayrıca, önceki konularda da bahsettiÄimiz gibi oluÅacak Spring Beanâlere çeÅitli kapsam (scope) belirlemeleri yapıyoruz. @Scope etiketi ile bir Spring Beanâin ne zaman ve nasıl yaratılacaÄını belirleyebiliyorduk.
âEmployeeSelectServiceImplâ sınıfını @Scope(value = âsingletonâ) yazarak bu sınıftan oluÅturulacak nesnenin uygulama ayakta kaldıÄı süre boyunca tek bir nesne olacaÄını söylüyoruz. Projenin herhangi bir yerinde bu sınıfa ait bir nesneyi baÄımlılık olarak talep ettiÄimizde Spring Context bu sınıfın aynı nesne referansını döndürecektir. Biliyoruz ki @Autowired etiketiyle nesne baÄımlılıÄını istediÄimiz sınıfta inject edebiliriz.
âEmployeeModificationServiceImplâ sınıfının kapsamını ise âprototypeâ olarak belirttik. Böylece, her @Autowired etiketiyle nesne baÄımlılıÄı eklediÄimizde Spring Context bu sınıftan yeni bir nesne üretip kullanıma sunacaktır.
**Spring ile Java Konsol Uygulaması ÃalıÅtırmak**
âcom.spring.basics.consoleâ Java packageâı oluÅturup bu paket altında Java konsol uygulaması olarak çalıÅacak sınıfı tasarlayacaÄız.
Spring Boot üzerinden bir sınıfı konsol uygulaması olarak çalıÅtırmak istersek Spring Frameworkâün âCommandLineRunnerâ interfaceâinden kalıtım alması gerekecektir.
âConsoleApplicationâ isminde sınıfı oluÅturuyoruz.
```java
public void run(String... args) throws Exception {
List employees = employeeSelectService.getAll();
System.out.println(employees);
employeeSelectService.findById(1L);
employeeModificationService.save("Ahmet");
System.out.println("employeeModificationService address : " + employeeModificationService);
System.out.println("employeeModificationService2 address : " + employeeModificationService2);
System.out.println("employeeModificationService3 address : " + employeeModificationService3);
System.out.println("employeeSelectService address : " + employeeSelectService);
System.out.println("employeeSelectService2 address : " + employeeSelectService2);
System.out.println("employeeSelectService3 address : " + employeeSelectService3);
}
}
```
Konsol sınıfında birçok baÄımlılıÄa ihtiyacımız oluyor. ÃrneÄin Service katmanındaki sınıflara konsol uygulamasının bir baÄımlılıÄı var. Bu baÄımlılıkları @Autowired etiketi ile Spring Contextâten talep ediyor. Buna da Dependency Injection diyoruz.
**Spring Boot @Configuration Sınıfı**
Ardından uygulamamız için bir configuration sınıfı oluÅturuyoruz. Bu konfigürasyon sınıfında hangi Java paketlerini okuyup Spring Contextâe dahil etmemiz gerektiÄini belirteceÄiz.
âcom.spring.basics.configâ paketi altında âApplicationConfigâ isminde bir sınıf açıyoruz.
```java
@Configuration
@ComponentScan(basePackages = {
"com.spring.basics.dao.impl",
"com.spring.basics.console",
"com.spring.basics.service.impl"})
public class ApplicationConfig {
}
```
İlk olarak bir konfigürasyon sınıfı olduÄunu belirtmek için @Configuration etiketini kullanıyoruz. Böylece Spring Framework bunun bir konfigürasyon sınıfı olduÄunu anlıyor. GörüldüÄü gibi DAO, Service ve Console katmanındaki sınıflarımıza ait paketleri Spring Frameworkâün tarayıp Spring Bean olarak Spring Contextâe eklemesini saÄlıyoruz.
Ardından uygulamamızı çalıÅtırdıÄımızda aÅaÄıdaki sonuçları alıyoruz.

Mavi ile belirtilen bölge program çıktılarıdır. GörüldüÄü gibi âsingletonâ olarak iÅaretlediÄimiz âEmployeeSelectServiceImplâ sınıfından 3 kez @Autowired ile nesne baÄımlılıÄı aldık. GörüldüÄü gibi hep aynı nesne referansını döndürmüŠgözüküyor. âprototypeâ olarak scope verdiÄimiz âEmployeeModificationServiceImplâ sınıfından ise 3 kez yine @Autowired etiketi ile nesne baÄımlılıÄı talep ediyoruz. Spring Context her istekte yeni bir nesne yaratıp bize vermiÅ oluyor.
**Spring AOP ile GeliÅtirme**
Aspect Oriented Programming yaklaÅımıyla uygulamamızda Cross Cutting Pointâler (kod üzerinde belli kesiÅim noktaları) belirleyerek, bu kesiÅim noktalarında istenilen kodların otomatik olarak çalıÅtırılmasını saÄlar. ÃrneÄin, Spring Frameworkâte yer alan @Transactional etiketi arka planda bir Aspect ile iliÅkili Åekilde çalıÅır. Böylece, her fonksiyon baÄlamadan önce ve bittikten sonra transaction baÄlatma veya baÅarılı/baÅarısız sonlandırma gibi iÅlemleri yapar.
Aynı Åekilde örneÄin projede yazdıÄınız her fonksiyonun çalıÅma süresinin ölçülmesinin istendiÄini düÅünün böyle bir durumda her fonksiyonun içine birtakım kodları yazmak zorundayız. Fonksiyonun çalıÅmaya baÅladıÄı noktada bir kronometre baÅlatıp, fonksiyon bittiÄinde ise kronometreyi durdurup süreyi ölçmek isteriz. Bu amacı gerçekleÅtirmek için her fonksiyona bu kodları yazmaya kalkarız.
Bu cidden maliyetli ve sıkıcı bir iÅ olurdu. Oysaki bizim yerimize bu kodları her fonksiyon çaÄrımında otomatik olarak iÅleten bir mekanizma olsa harika olmaz mıydı? İÅte AOP bize bu fırsatı sunuyor. Bu tarz durumlarda gerektiÄinde otomatik olarak çalıÅmasını istediÄimiz kodları devreye alıyor. Sonrasında iÅi bitince kodun akıÅını ve iÅletim sorumluluÄunu bizim yazdıÄımız koda devrediyor.
Yukarıda yaptıÄımız projede her fonksiyonun süresini ölçmek için bir kurgu tasarlayalım. Ãncelikle kesiÅim noktalarını ifade etmek için bir Java Annotation yazacaÄız ve hangi fonksiyonun süresini ölçmek istersek onun tepesine bu etiketi yazacaÄız. Böylece süresini ölçmek istediÄim fonksiyonları deklaratif bir biçimde ifade etmiÅ olacaÄım. Bu etiketi kullandıÄım noktalar AOP için bir Cross Cutting Point olacaktır. Yani kesiÅim noktalarımız olacaktır.
İlk iŠolarak basit bir Java etiketi tanımlayalım.
```java
âcom.spring.basics.annotionâ Java paketi altında âMethodRunningTimeâ isminde bir Java etiketi tanımlıyoruz. Javaâda etiket tanımlamak için @interface ifadesi kullanılır.
@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD })
public @interface MethodRunningTime {
boolean active();
}
```
TanımladıÄımız Java etiketin bazı alanları inceleyelim. @Retention etiketiyle tanımladıÄımız etiketin ne zaman ne yöntemle çalıÅacaÄını belirtiyoruz. RUNTIME Åeklinde belirterek etiketimizin Reflection yöntemiyle çalıÅma zamanında kullanılabilir hale geleceÄini söylüyoruz. @Target etiketi ile ise tanımladıÄımız âMethodRunningTimeâ isimli Java etiketinin hangi bölgelerde kullanılabileceÄini belirtiyoruz.
ÃrneÄin METHOD olarak belirttiÄimiz bir Java etiketini sadece fonksiyonlar için kullanabiliriz. Bu etiketi fonksiyon tanımının üstüne yazabilirim demek oluyor. Bu etiketi sınıf tanımı üstüne yerleÅtiremem buna izin vermeyecektir. Sebebi ise dediÄimiz gibi METHOD olarak iÅaretleyip sadece fonksiyonların üstünde tanımlanabilir olmasıdır.
Etiketin içinde active isminde bir boolean deÄiÅken bulunmaktadır. active = true olarak kullanılmıŠetiketlere baÄlı fonksiyonların süre ölçümü yapılabilir. Fakat, active = false olarak belirtilmiÅ ise bu etiketi baÄlı fonksiyonun süre ölçümü yapılmaz.
Ardından âcom.spring.basics.aspectâ Java paketi tanımlanıp yukarıda tasarladıÄımız âMethodRunningTimeâ isimli etiket için bir Aspect hazırlamamız gerekmektedir. Bu Aspect içine yazdıÄımız kodlar etiket ile iÅaretlenmiÅ fonksiyonlar çalıÅmadan önce ve sonra devreye girip otomatik olarak iÅletilecektir. Aspectâin yapacaÄı iÅ fonksiyonun çalıÅma süresini ölçmek olacaktır.
```java
@Aspect
@Component
public class MethodRunningTimeAspect {
@Around("@annotation(methodRunningTime1)")
public Object execute(ProceedingJoinPoint point, MethodRunningTime methodRunningTime1) throws Throwable {
if(!methodRunningTime1.active()) {
return point.proceed();
}
String className = point.getSignature().getDeclaringType().getSimpleName();
String methodName = point.getSignature().getName();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object result = point.proceed();
stopWatch.stop();
System.out.println(className + "#" + methodName + " runned in " + stopWatch.getTotalTimeMillis() + " ms");
return result;
}
}
```
@Aspect etiketiyle sınıfımızın bir Aspect olarak kullanılacaÄını Spring Frameworkâe iletiyoruz. Ardından bu Aspectâin Spring Contextâde yönetilebilir bir baÄımlılık olması için @Componet etiketiyle iÅaretliyoruz.
Sınıfın içinde tasarladıÄımız âexecuteâ isimli fonksiyon içindeki kodlar âMethodRunningTimeâ etiketiyle kestiÄimiz fonksiyonlar çaÄrıldıÄında iÅletilecek olan Java kodlarıdır. Bu Java kodları fonksiyonun çalıÅma süresini ölçecektir. âexecuteâ içindeki kodlar kestiÄimiz fonksiyon çaÄrılmadan önce ve çaÄrıldıktan sonra otomatik olarak Spring Framework tarafından iÅletilecektir.
@Around etiketi ile kestiÄimiz fonksiyonun çaÄrılmasından önce ve sonra birtakım iÅlemler yapacaÄımızı söylüyoruz. @Around etiketi içinde â@annotation(methodRunningTime1)â ifadesiyle âMethodRunningTimeâ tipindeki etiket ile kesiÅmiÅ olan fonksiyonlarda çalıÅabilirsiniz diyoruz. Yani aslında Aspect hangi koÅulda âexecuteâ fonksiyonu içindeki kodları çalıÅtıracaÄını belirtiyoruz.
@Around yerine aÅaÄıdaki etiketleri de kullanabilirdik:
@Before etiketi ile fonksiyon çaÄrılmadan önce birtakım komutlar iÅletebiliriz. Yine @Before etiketi AOP ile kullanılabilir. Sadece fonksiyon çaÄrılmadan önce iÅletilir ve sonrasında bir iÅlem yapmaz.
@After etiketi ile ise fonksiyon çaÄrımı bittikten sonra Aspect içindeki Java kodları devreye alınır ve çalıÅtırılır. Fonksiyonun çaÄrımından önce herhangi bir kod çalıÅtırılmaz. @Before etiketinin tam tersidir.
## **@MethodRunningTime Etiketinin Kullanımı**
```java
@MethodRunningTime(active = true)
@Override
public List getAll() {
return employeeDAO.getAll();
}
@MethodRunningTime(active = false)
@Override
public String findById(Long id) {
return employeeDAO.findById(id);
}
```
GörüldüÄü gibi tanımlanan herhangi bir fonksiyonun üstüne @MethodRunningTime isimli etiketimizi kullanıp fonksiyonun çalıÅma süresinin Aspect tarafından ölçülmesini saÄlayabiliriz. @MethodRunningTime etiketiyle kestiÄimiz her fonksiyon AOP açısından bir kesiÅim noktasıdır. Bu kesim noktalarında Aspectâe ait Java kodları otomatik olarak Spring tarafından iÅletilir.
âactive = falseâ olarak belirtilmiÅ etiketlerin kestiÄi fonksiyonların çalıÅma süresi ölçümü yapılmayacaktır.