10 Ağustos 2017 Perşembe

Spring'te Dependency Injection

Merhaba arkadaşlar,

Bu yazımda Dependency Injection'ın Spring framework'te nasıl uygulandığını anlatmaya çalışacağım.

Bildiğiniz gibi dependency injection class'ların birbiriyle olan bağımlılıklarını azalmak için kullanılan bir yöntemdir. 

Örnek verecek olursak;

Elimizde "A" ve "B" class'ları olsun. "A" class'ında "B" nesnesi üretildiğini düşünelim. Şuan "A" class'ı "B" class'ına bağlı hale geldi. Bunların bağımlılıklarını azaltmamız gerekmektedir. Bu sebepten A class'ı içinde bir B nesnesini new anahtar kelimesiyle yaratmak yerine dışarıdan bunu vereceğiz.  


Dışarıdan verebilmemiz için setter veya constructor kullanmamız gerekmektedir. 

Peki bu constructor veya setter methodu içine B class'ı tipinde bir nesne mi alması gerekiyor? Tabikide hayır. 

Bu işlem şu şekilde olmalıdır.

A class'ı setter metodu veya constructor'a bir interface tipinde nesne istemeli. Bu interfce tipindeki nesnenin ismini Ib olarak tanımladık diyelim. 

Daha sonra B class'ı bu Ib interfacesini implement edip gerekli metodlarını override eder. Şuan B nesnesi Ib interfacesini impelemt ettiği için A class'ınının setter'ına veya constructor'ına parametre olarak geçilebilir. 

Peki A setter veya constructor Ib interface nesnesini parametre olarak isterken nasıl B class'ı tipinde bir nesneyi parametre olarak gönderebileceğiz?

Bu sorunun cevabı Java tarafından sağlanan POLIMORFIZM'dir. Anlayamayanlar java polimorfizm konusunu detaylı incelemelidir.

Eğer yapıyı bu şekle getirebilirsek bir C class'ı eğer Ib interfacesini implement edip, gerekli metodları override ederse, C class'ını da A setter metod veya constructor'a parametre olarak geçebiliriz. 

( Parametre olarak geçirilen kısım Ib interfacesine casting ediliyor diye düşünebiliriz.)

Biraz kafanız karışmış olmuş olabilir. Bu konuyu daha iyi anlamak için öncelikle Dependency Injection ( DI ) yazımı okumalıdır.


Spring DI

Spring framework'ünün en büyük özelliklerden birisi dependency injection desteği sağlamasıdır.

Spring'de iki tür injection vardır. Bunlar Setter Injection ve Constructor Injection.

Örnek üzerinden açıklamaya çalışa.


1.Setter Injection





import java.util.List;
 
public class SearchEngine1
{
    private Search searchAlgorithm;
     

     
    public Search getSearchAlgorithm() {
        return searchAlgorithm;
    }
 
    public void setSearchAlgorithm(Search searchAlgorithm) {
        this.searchAlgorithm = searchAlgorithm;
    }   
 
 
     public boolean search( List<Integer> list, int id )
    {
        return searchAlgorithm.find(list, id);
    }
     
}
import java.util.List;
 
public interface Search 
{
    public boolean find( List<Integer> list,  int id );
}

SeachEngine1 class'ını incelediğimzde  Search tipinde searchAlgorithm isminde bir değişkene sahip olduğunu görüyoruz. Bu nesnenin dependency injection mantığı gereği dışarıdan verilmesi gerekmektedir. Ayrıca esneklik sağlanması için Search tipi bir interface tipi olması gerekmektedir. Böylelikle Search interfacesini implement eden her class setSearchAlgorithm metoduna parametre olarak geçilebilir. ( polimorfizm ) ( sanki Search interfacesine cast ediliyormuş gibi düşünülebilir.)



import java.util.Collections;
import java.util.List;

public class BinarySearch implements Search 
{
    @Override
    public boolean find(List<Integer> list, int id) 
    {
        System.out.println("Binary Search");
         
        Collections.sort( list );       
        return Collections.binarySearch(list, id)>=0;
    }   
}

Kodu incelersek, BinarySearch class'ı Search class'ını implement etmiş ve find methodunu Override edip kendi search tipini bu metoda uygulamış.






import java.util.List;
 
public class SequentialSearch implements Search
{
    @Override
    public boolean find(List<Integer> list, int id) 
    {   
        for( Integer i : list )
        {
            if( i == id )
                return true;
        }
         
        System.out.println("Sequential Search");
         
        return false;
    }
         
}  
SequentialSearch class'ını incelersek, Search interfacesini implement etmiş ve find() metodunu Override etmiş. find() metoduna kendi search algoritmasını uygulamış.


BinarySearch ve SequentialSearch class'larını incelersek ikiside Search interfacesini implement etmiş. Yani  ikiside SearchEngine1 classında bulunan Search searchAlgorithm nesnesinin set edilmesi için kullanılan setSearchAlgorithm( ) metoduna parametre olarak verilebilir. Çünkü bu iki class'ta Search interfacesini implement edip ilgili metodu override etmiş durumdalar. 

Bu özellik bize SearchEngine1 class'ının setter metoduna verilen algoritma tipine göre search yeteneği kazandırmış oldu. Bu sayede esnelik kazandık. İleride başka bir search algoritması üretilip uygulanmak istenirse SearchEngine1 içinde hiçbir değişiklik yapılmadan uygulanabilir.


Şimdi sıra geldi Spring'te bunu uygulamaya. Spring'te injection özelliği xml üzerinden yapılmaktadır.


<?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:context="http://www.springframework.com/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                      http://www.springframework.org/schema/context
                      http://www.springframework.org/schema/context/spring-context-3.2.xsd">
                            
    <bean id="binarySearch" class="com.serdarkocerr.spring.search.BinarySearch" />
    <bean id="sequentialSearch" class="com.serdarkocerr.spring.search.SequentialSearch" />
     
    <bean id="searchEngineV1" class="com.serdarkocerr.spring.search.SearchEngine1" >
        <property name="searchAlgorithm" ref="binarySearch" /> <!-- Setter Injection -->
    </bean> 
 
</beans> 
Yukarıdaki xml konfigürasyon dosyasını inceleyelim. Bütün class'lar bean olarak tanılmış. 

SearchEngine1 class'ı içerisinde deklare edilen 

private Search searchAlgorithm 

nesnesine bir atama yapılmalıdır. Yoksa nullPointerException hatası olur. Bu kısımda Spring'in bize sunduğu injection özelliği devreye girmektedir. Injection xml dosyasından direk yapılabilmektedir. Bu sayede bir nesne üretip setter fonksiyonuna gidip bir bir nesne üretip ardından  nesneyi parametre olarak vermiyoruz. Hiç böyle kodlamalara girmeden Xml üzerinden rahat bir şekilde yapıyoruz. 

searchAlgorithm  interface nesnesine referans verilirken interface nesnesi gerekmektedir. Bean olarak tanıtılmış olan binarySearch ve sequentialSearch class'ları bu interfaceyi implement ettiğinden referans olarak verilebilir. Bu kısım bize Dependency Injection'ı sağlar.  Çünkü referans olarak bu interfaceyi implement etmiş her nesneyi verebiliriz. Bize  esneklik sağlar. İleride üretilecek başka search algoritmaları için searchEngine1 içinde değişiklik yapılmadan  uygulanabilirlik sağlanmış olur.


Setter injection da ilgili interface nesnesi için setter metodu yazılması gerekiyor. Bu setter metounun beklediği nesnenin ismi (Search searchAlgorithm)  ile referans olarak verilen isim name="searchAlgorithm" aynı olmalıdır. Yani hangi isme karşılık referans olarak bu bean veriliyorun cevabı gibi düşünülebilir.

Sonuç olarak setter fonksiyonuna verilen parametrenin ismi ise bean'de verilen referansın ismi aynı olmalıdır.


2.Constructor Injection

Bu injection tipinde constructorlar üzerinden dependency injection uygulanır.



import java.util.List;
 
public class SearchEngine2
{
    private Search searchAlgorithm;
     
    public SearchEngine2( Search searchAlgorithm )
    {
        this.searchAlgorithm = searchAlgorithm;
    }
     
    public boolean search( List<Integer> list, int id )
    {
        return searchAlgorithm.find(list, id);
    }
} 



<?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:context="http://www.springframework.com/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                      http://www.springframework.org/schema/context
                      http://www.springframework.org/schema/context/spring-context-3.2.xsd">
                            
    <bean id="binarySearch" class="com.serdarkocerr.spring.search.BinarySearch" />
    <bean id="sequentialSearch" class="com.serdarkocerr.spring.search.SequentialSearch" />
     
     
    <bean id="searchEngineV2" class="com.serdarkocerr.spring.search.SearchEngine2" >
          <constructor-arg name="searchAlgorithm" ref="sequentialSearch" />
    </bean>
 
</beans> 

SearchEngine2 class'ına dikkat edilirse constructor içine bir Search interface tipinde nesne alıyor. 

.xml dosyasını incelersek SearchEngine2 beanı tanımlanırken constructor üzerinden bir referans verilmiş. Bu referans  bean id olarak verilir. sequentialSearch bean id'yi temsil eden SequentialSearch class'ı ise Search interfacesini implement etmişti yani referans olarak verilebilir. Başka bir search algoritması da eğer Search interfacesini implement ettiyse constructor'a  parametre olarak geçilebilir. Bu sayede büyük bir esneklik kazanmış oluyoruz. Dependency Injection bu şekilde sağlanmış oluyor.




Örneklerimizde hem Setter hem de Constructor Injection özelliklerini kullanarak Dependency Injection mimarisini başarı bir şekilde uygulamış olduk. Spring bize injection bakımından çok fazla kodlama yapmamız konusunda yardımcı oluyor.

Aşağıdaki constructor'ı incelersek

Search tipinde bir interface constructor'a parametre olarak verilmeli.
İsmine dikkat edersek  nesnenin ismi searchAlgorithm


    public SearchEngine2( Search searchAlgorithm )
    {
        this.searchAlgorithm = searchAlgorithm;
    }
     
Daha sonra aşağıdaki bean tanımlamasını incelersek,

constructor 'a bir referans geçilmeli. Bu referans geçilecek nesnenin ismi searchAlgorithm olduğunu görmekteyiz.


    <bean id="searchEngineV2" class="com.serdarkocerr.spring.search.SearchEngine2" >
          <constructor-arg name="searchAlgorithm" ref="sequentialSearch" />
    </bean>

Yani sonuç olarak constructor'a tanıtılan parametre isimleri hep aynı olmalıdır.





Kaynaklar:

http://www.kazimsoylu.com/java/spring-framework-ile-dependency-injection.html




Spring Autowiring - Annotation ( @Autowired )

Merhaba arkadaşlar,


Bu yazımda daha önce Spring Autowiring-XML yazımda bahsettiğimden farklı olarka autowiring işlemini annotation üzerinden nasıl yapılacağına değineceğim.


Annotation ile autowiring işlemi için @Autowired  annotation'ı kullanılır.

Bir bean ile autowiring yapabilmek için @Autowired annotation'ı setter metod, constructor veya bir nesnede kullanılmalıdır.

Aşağıdaki örnekleri inceleyelim.

Öncelikle bean'leri oluşturuyoruz.


public class Ogrenci {

 private String ogrenciad;
 private String ogrencisoyad;
 private String numara;
 private String okulad;

 
 
 public String getOgrenciad() {
  return ogrenciad;
 }
 public void setOgrenciad(String ogrenciad) {
  this.ogrenciad = ogrenciad;
 }
 public String getOgrencisoyad() {
  return ogrencisoyad;
 }
 public void setOgrencisoyad(String ogrencisoyad) {
  this.ogrencisoyad = ogrencisoyad;
 }
 public String getNumara() {
  return numara;
 }
 public void setNumara(String numara) {
  this.numara = numara;
 }
 public String getOkulad() {
  return okulad;
 }
 public void setOkulad(String okulad) {
  this.okulad = okulad;
 }
 
 
}

package com.serdarkocerr.SpringExample;


public class Ders {

 /**/
 private Ogrenci ogrenci;
 private String dersad;
 
 public String getDersad() {
  return dersad;
 }
 public void setDersad(String dersad) {
  this.dersad = dersad;
 }
 
 
}
Class'ları oluşturduktan sonra bunları Spring-Module.xml içerisinde bean olarak tanıtıyoruz.


Spring-Module.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">


 <bean id="ogr" class="com.serdarkocerr.SpringExample.Ogrenci">
  <property name="ogrenciad" value="Serdar" />
  <property name="ogrencisoyad" value="Kocer" />
  <property name="numara" value="821" />
  <property name="okulad" value="Arifiye AOL" />
 </bean>
 
 
 <bean id="ders" class="com.serdarkocerr.SpringExample.Ders" >
  <property name="dersad" value="Matematik" />
 </bean>
 

</beans>

Bu haliyle id="ders" olan bean'den bir nesne oluşturmaya çalışırsak Ders içerisinde bulunan Ogrenci ogrenci nesnesine herhangi bir autowiring (injection )yapılmadığından

 org.springframework.beans.factory.BeanCreationException:

hatasını alırız.

Autowiring işlemine geçmeden önce Annotation ile autowiring yapacağımızı Spring-Module.xml içerisinde belirtmemiz gerekmektedir.

<context:annotation-config />

Spring-Module.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">


 <context:annotation-config />

 <bean id="ogr" class="com.serdarkocerr.SpringExample.Ogrenci">
  <property name="ogrenciad" value="Serdar" />
  <property name="ogrencisoyad" value="Kocer" />
  <property name="numara" value="821" />
  <property name="okulad" value="Arifiye AOL" />
 </bean>
 

 
 <bean id="ders" class="com.serdarkocerr.SpringExample.Ders" >
  <property name="dersad" value="Matematik" />
 </bean>
 

</beans>
Ayrıca Maven projesi kullanıyorsanız pom.xml'e aşağıdaki dependency'leri eklemelisiniz.


<!-- Spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>



Autowiring Uygulamaları:

Spring-Module.xml'i bu şekilde annotation autowiring yapabilecek şekle getirdikten sonra autowiring işlemlerine geçebiliriz.

Ogrenci class'ı yukarıdaki gibi olmalıdır. Bu kısımda @Autowired annotation'ı autowire işlemi olacak kısma eklenir yani Ders class'ı içine.

Annotation ile 3 şekilde autowiring yapabilir. Aşağıda örneklerle açıklanmıştır.

1. @Autowired Setter metod




package com.serdarkocerr.SpringExample;

import org.springframework.beans.factory.annotation.Autowired;

public class Ders {

 /*AutoWiring Ozelligi XM@annotation ile*/
 
 private Ogrenci ogrenci;
 private String dersad;
 
 
 public Ogrenci getOgrenci() {
  return ogrenci;
 }
 @Autowired
 public void setOgrenci(Ogrenci ogrenci) {
  this.ogrenci = ogrenci;
 }
 public String getDersad() {
  return dersad;
 }
 public void setDersad(String dersad) {
  this.dersad = dersad;
 }
 
 
}

Kırmızı bold alanlara dikkat et!

Yukarıdaki class'a bakıldığında bir nesne olarak tanıtılmıs ogreci değişkeninin setter metodunun üstüne @Autowired annotation'ı eklenmiş.

@Autowired annotation'ı Spring-Module.xml içerisinde ilgili bean'ı buluyor. ( Class ismine göre buluyor sanki byType gibi.) Bulduğu bean ile autowiring işlemi uyguluyor.



2. @Autowired Constructor


package com.serdarkocerr.SpringExample;

import org.springframework.beans.factory.annotation.Autowired;

public class Ders {

 /*AutoWiring Ozelligi @Annotation ile*/
 
 private Ogrenci ogrenci;
 private String dersad;
 
 
 public Ogrenci getOgrenci() {
  return ogrenci;
 }
 
 @Autowired
 public Ders(Ogrenci ogrenci) {
  super();
  this.ogrenci = ogrenci;
 }

 public String getDersad() {
  return dersad;
 }
 public void setDersad(String dersad) {
  this.dersad = dersad;
 }
 
 
}


Yukarıdaki kod incelendiğinde @Autowired işlemi constructor'ın üstüne tanımlanmış Constructor ise bir nesne tipinde tanımlanmış değişkeni içinde set ediyor yani setter gibi işlem görüyor. Spring-Module.xml dosyasında @Autowired yapılan nesnenin class ismi ( Ogrenci class'ı )  aranıp autowiring işlemi uygulanıyor.



3. @Autowired Değişken



package com.serdarkocerr.SpringExample;

import org.springframework.beans.factory.annotation.Autowired;

public class Ders {

 /*AutoWiring Ozelligi @Annotation ile */
 @Autowired
 private Ogrenci ogrenci;
 private String dersad;
 
 
 public Ogrenci getOgrenci() {
  return ogrenci;
 }


 public String getDersad() {
  return dersad;
 }
 public void setDersad(String dersad) {
  this.dersad = dersad;
 }
 
 
}

Yukarıdaki örneği incelersek,  Ogrenci tipinde oluşturulan nesneye @Autowired annotation'ı ile autowiring işlemi uygulanmış.

Spirng-Module.xml dosyasında bu nesne tipindeki bean bulunacak ve autowiring işlemi uygulanacak.



@Qualifier  Annotation


Bu annotation bize iki tane aynı class isimine sahip fakat id'leri birbirinden farklı ( bean id'leri her zaman uniqe olmalıdır.) bean var ise @Autowired annotation'ı kullanıldığında hangi bean'i seçeceğini belirtir. @Autowired annotation'ı autowiring işlemini class ismine göre yaptığından ve aynı isimde iki class birden olduğundan bunlar arasında ayrım yapamaz. Ek olarak bir bilgi daha gerekmektedir. Bu bilgi ise @Qualifier Annotation'ı ile sağlanır.



Spring-Module.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">


 <context:annotation-config />

 <bean id="ogr1" class="com.serdarkocerr.SpringExample.Ogrenci">
  <property name="ogrenciad" value="Serdar" />
  <property name="ogrencisoyad" value="Kocer" />
  <property name="numara" value="821" />
  <property name="okulad" value="Arifiye AOL" />
 </bean>
 
 <bean id="ogr2" class="com.serdarkocerr.SpringExample.Ogrenci">
  <property name="ogrenciad" value="Hakan" />
  <property name="ogrencisoyad" value="Kocer" />
  <property name="numara" value="10" />
  <property name="okulad" value="Kocaeli AOL" />
 </bean>

 
 <bean id="ders" class="com.serdarkocerr.SpringExample.Ders" >
  <property name="dersad" value="Matematik" />
 </bean>
 

</beans>




package com.serdarkocerr.SpringExample;

import org.springframework.beans.factory.annotation.Autowired;

public class Ders {

 /*AutoWiring Ozelligi @Annotation ile */
 @Autowired
 @Qualifier("ogr2")
 private Ogrenci ogrenci;
 private String dersad;
 
 
 public Ogrenci getOgrenci() {
  return ogrenci;
 }


 public String getDersad() {
  return dersad;
 }
 public void setDersad(String dersad) {
  this.dersad = dersad;
 }
 
 
}


Yukarıdaki örneğer dikkat edersek Spring-Module.xml içerisinde

com.serdarkocerr.SpringExample.Ogrenci
class'ından iki tane bean tanımlanmış.

Ders class'ında tanımlanan Ogrenci tipindeki nesnenin @Autowired ile hangi bean'e autowiring olacağını ek olarak söylememiz gerekmektedir. Çünkü @Autowired annotation'ı autowiring işlemini xml içinde belirlenen beanlerin class ismine göre yapmaktadır. Bu sebepten Ders class'ı içinde



@Qualifier("ogr2")

@Qualifier annotation'ı ile id="ogr2" olan bean'ı autowiring edecektir.  Yani output olarak;


Hakan
Kocer
100
Izmit AOL
Matematik

çıktısı alınacaktır.



Kaynaklar:

https://www.mkyong.com/spring/spring-auto-wiring-beans-with-autowired-annotation/















Spring Autowiring - XML

Merhaba,

Bu yazımda beanleri tanıttığımız xml dosyası üzerinden autowiring tanımlamalarını anlatacağım.

Neden autowiring kullanırız?

Önceki yazılarımda Spring üzerinde Dependency Injection konusuna değindiğimde, bağımlılıkları enjekte ederken Spring xml dosyasında bean bağımlılıklarında <constructor-arg>, <property> attributlerini kullanıyorduk. Bu işlem yazılımımız büyüdükçe tekrar tekrar aynı şeyleri Spring xml dosyasına girmemize neden olacak ve yönetilmesi zorlaşmaya başlayacaktır.

Autowiring ile bağımlılıklar otomatik olarak injecte edilerek xml bağımlılığı en aza indirgenmektedir.


Autowiring Çeşitleri

1) Auto-wire no:


Varsayılandır. Bağımlılıklar tek tek yazılır. Yani bean'leri bağlamak için "ref" attribute kullanılır.

<bean id="musteri" class="com.serdarkocerr.Customer">
                  <property name="kisi" ref="kisi" />
</bean>

<bean id="kisi" class="com.serdarkocerr.Person" />


2) Auto-wire byName:

Autowiring işlemi, beanı isime göre otomatik olarak bağlar.

Aşağıdaki örneği inceleyelim.


public class Ogrenci {

 private String ogrenciad;
 private String ogrencisoyad;
 private String numara;
 private String okulad;

 
 
 public String getOgrenciad() {
  return ogrenciad;
 }
 public void setOgrenciad(String ogrenciad) {
  this.ogrenciad = ogrenciad;
 }
 public String getOgrencisoyad() {
  return ogrencisoyad;
 }
 public void setOgrencisoyad(String ogrencisoyad) {
  this.ogrencisoyad = ogrencisoyad;
 }
 public String getNumara() {
  return numara;
 }
 public void setNumara(String numara) {
  this.numara = numara;
 }
 public String getOkulad() {
  return okulad;
 }
 public void setOkulad(String okulad) {
  this.okulad = okulad;
 }
 
 
}
package com.serdarkocerr.SpringExample;


public class Ders {

 /*AutoWiring Ozelligi XML de*/
 private Ogrenci ogrenci;
 private String dersad;
 
 public Ogrenci getOgrenci() {
  return ogrenci;
 }
 public void setOgrenci(Ogrenci ogrenci) {
  this.ogrenci = ogrenci;
 }
 public String getDersad() {
  return dersad;
 }
 public void setDersad(String dersad) {
  this.dersad = dersad;
 }
 
 
}
İki tane class tanımlandı. Dikkat edersek Ders class'ının değişkeni Ogrenci nesnesi şeklinde tanımlanmış. Bu durumda öğrenci nesnesi tanımlanmalıdır ama dependency injection gereği bu nesne class'ın içinde tanımlanmaz. Dışarıdan tanımlanır verilir. 

Spring'te bu tanımlamalar xml üzerinden yapıldığını biliyoruz. Aşağıda verilen xml dosyasını inceleyelim.


Spring-Module.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

 
 <bean id="ogrenci" class="com.serdarkocerr.SpringExample.Ogrenci">
  <property name="ogrenciad" value="Serdar" />
  <property name="ogrencisoyad" value="Kocer" />
  <property name="numara" value="821" />
  <property name="okulad" value="Arifiye AOL" />
 </bean>
 
 
 <bean id="ders" class="com.serdarkocerr.SpringExample.Ders" autowire="byName">
  <property name="dersad" value="Matematik" />
 </bean>
 

</beans>
Kırmızı bold alanlara dikkat et!

Spring-Module.xml dosyasını inceledeğimizde Ders class'ından tanımlanan bean'de bir autowiring işlemi olduğu görülüyor. Yani Ders class'ı içerisinde değişken olarak bir class tipinde nesne tanıtılmış.  Autowire = "byName" olduğundan Ders class'ında tanımlanan nesne tipindeki değişkenin ismi ile bean tanımlamasında kullanılan id aynı olmalıdır.

Dikkatli incelersek  Ders class'ının hem Set fonksiyonunda hemde nesne tanımlamasında

Ogrenci ogrenci

şeklinde tanımlanmış.



Detay Bilgi:

Auto-wire işlemi olabilmesi için set/get metodları tanımlanmalıdır. Hem auto-wire eden hemde auto-

wire edilen classların ikisinde birden bu tanımlama olmalıdır. byName ile yapılırken Setter/Getter 

üzerinden yapılır. 

Yani setter metodunun parametresi ile bean id aynı isimde olmalıdır. Ayrıca class değişkeninin 

ismide aynı olmalıdır.


3) Auto-wire byType:


Bir bean ile auto-wire işlemi nesne tipine göre olur.

Aşağıdaki örneği inceleyelim.

Ogrenci ve Ders class'ları yukarıdaki gibidir bir değişiklik yoktur. Sadece xml de aşağıdaki değişiklikler olmuştur.


Spring-Module.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

 
 <bean id="ogr" class="com.serdarkocerr.SpringExample.Ogrenci">
  <property name="ogrenciad" value="Serdar" />
  <property name="ogrencisoyad" value="Kocer" />
  <property name="numara" value="821" />
  <property name="okulad" value="Arifiye AOL" />
 </bean>
 
 
 <bean id="ders" class="com.serdarkocerr.SpringExample.Ders" autowire="byType">
  <property name="dersad" value="Matematik" />
 </bean>
 

</beans>
Kırmızı bold alanlara dikkat et!


ByType ile autowiring işleminde Ders class'ı içerisinde tanımlanan Ogrenci tipindeki nesne ile autowire işlemi,  Ogrenci tipine yani nesnenin tanımlanma tipine göre olur. Dikkat edilirse id diğer örnekten farklı çünkü burada byName değilde byType şeklinde autowiring işlemi var.



4) Auto-wire  constructor:

Constructor üzerinden autowiring işlemi yapılır.




public class Ogrenci {

 private String ogrenciad;
 private String ogrencisoyad;
 private String numara;
 private String okulad;

 
 
 public String getOgrenciad() {
  return ogrenciad;
 }
 public void setOgrenciad(String ogrenciad) {
  this.ogrenciad = ogrenciad;
 }
 public String getOgrencisoyad() {
  return ogrencisoyad;
 }
 public void setOgrencisoyad(String ogrencisoyad) {
  this.ogrencisoyad = ogrencisoyad;
 }
 public String getNumara() {
  return numara;
 }
 public void setNumara(String numara) {
  this.numara = numara;
 }
 public String getOkulad() {
  return okulad;
 }
 public void setOkulad(String okulad) {
  this.okulad = okulad;
 }
 
 
}



package com.serdarkocerr.SpringExample;


public class Ders {

 /*AutoWiring Ozelligi XML de*/
 private Ogrenci ogrenci;
 private String dersad;
 

 public Ders(Ogrenci ogrenci) {
  super();
  this.ogrenci = ogrenci;
 }
 
 public Ogrenci getOgrenci() {
  return ogrenci;
 }
 public String getDersad() {
  return dersad;
 }
 public void setDersad(String dersad) {
  this.dersad = dersad;
 }
 
 
}
Ders class'ına dikkat edersek Set methodu yok. Bunun yerine constructor  ile  Ogrenci nesnesini set edeceğiz.



Spring-Module.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

 
 <bean id="ogr" class="com.serdarkocerr.SpringExample.Ogrenci">
  <property name="ogrenciad" value="Serdar" />
  <property name="ogrencisoyad" value="Kocer" />
  <property name="numara" value="821" />
  <property name="okulad" value="Arifiye AOL" />
 </bean>
 
 
 <bean id="ders" class="com.serdarkocerr.SpringExample.Ders" autowire="constructor">
  <property name="dersad" value="Matematik" />
 </bean>
 

</beans>
                                                                            Kırmızı bold alanlara dikkat et!

Spring-module.xml içerisine bakacak olursak autowire işlemi "constructor" olarak seçilmiş. Bu demek oluyor ki Ders class'ı içerisine bir nesneye constructor üzerinden autowire işlemi uygulanacak.




4) Auto-wire  autodetect:


Default olarak constructor üzerinden autowiring işlemi yapar.  Eğer constructor yoksa byType olarak autowiring işlemi yapar.

Ogrenci ile Ders class'ı auto-wire constructor'daki gibi olsun.


Spring-Module.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

 
 <bean id="ogr" class="com.serdarkocerr.SpringExample.Ogrenci">
  <property name="ogrenciad" value="Serdar" />
  <property name="ogrencisoyad" value="Kocer" />
  <property name="numara" value="821" />
  <property name="okulad" value="Arifiye AOL" />
 </bean>
 
 
 <bean id="ders" class="com.serdarkocerr.SpringExample.Ders" autowire="autodetect">
  <property name="dersad" value="Matematik" />
 </bean>
 

</beans>
                                                                            Kırmızı bold alanlara dikkat et!


Spring-Module.xml'e dikkat edilirse autowire "autodetect" olarak seçilmiş durumdadır. Autodetect'te default olarak constructor üzerinden eğer constructor yoksa  byType olarak autowiring işlemi yapılır.

Bu örnekte constructor üzerinden autowire yapacaktır.


ÖNEMLİ DETAY:
Mesela Databaseye Spring MVC XML konfigürasyonu ile veri kaydedeceğiz. BU Databasede kullanmak üzere DAO Design Pattern'nini kullanacağız. DAO Imp sınıfında xml de tanıttığımız bir değişkeni @Autowired ile bağladık. Ardından bu DAOImp sınıfından bir nesne yaratmak ve databasete kayıt işlemi gerçekleştirmek istiyoruz. Bu nesne yaratımını eğer new();  ile yaparsak içerisinde kullandığımız @Autowired edilen nesne xml de verdiğimiz bean değerlerini alamaz. Çünkü bu durumda yani new ile yaratma durumunda nesneyi Spring kontrol etmez yani konfigüre edemez. Kendimiz yaratmış oluruz. Bunun önüne geçmek için DAOImp sınıfınıda xml de bean olarak tanıtıyoruz ve new(); olarak kullanacağımız yerde new(); yerine @Autowired ile DAOImp sınıfını yaratıp içerisinde bulunan @Autowired değişkenlerinin Spring tarafından xml de belirtilen bean değerlerini almasını sağlarız.

Yani sonuç olarak, bir nesneyi yaratırken eğer içerisinde @Autowired şeklinde Spring tarafından kontrol edilen(inject edilen) değişkenler, nesneler vs. varsa yaratacağımız nesneyi new();   ile değilde xml de bean olarak tanıtıp, kullanılacak yerde nesne deklare edilip ardından @Autowired  yapılmalıdır.

Yoksa NullPointerException hatası alınır.

https://stackoverflow.com/questions/35302501/jdbctemplate-is-null-and-throws-null-pointer-exception

http://forum.spring.io/forum/spring-projects/data/69318-getting-null-pointer-exception-while-using-jdbc-template

Kaynaklar:

http://www.mkyong.com/spring/spring-auto-wiring-beans-in-xml/
http://blog.burakkutbay.com/spring-dersleri-autowiring-nedir-kullanimi.html/

9 Ağustos 2017 Çarşamba

Spring MVC ile Hello World Örnegi

Merhaba arkadaşlar,

Bir önceki yazımda Spring MVC konusu üzerine açıklamar yapmıştım. Bu yazımda ise Hello World Örnegi üzerinden işleyişine deginecegim.


Tomcat 8
Spring 4.3.7 
JDK 1.8 

1.Adım: İlk olarak Eclipse'ı açıp Dimanik Web Projesi oluşturuyoruz.





Projeyi oluşturktan sonra bunu Maven projesine dönüştürüyoruz.






Web.xml eklemek için ise;




2.Adım: 
Bu işlemlerden sonra Maven projemiz hazır hale geliyor.


Spring kütüphaneleri için pom.xml aşagıdaki gibi olmalıdır.


pom.xml
<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>SpringMVCHelloWorld</groupId>
<artifactId>SpringMVCHelloWorld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>


-----------------------------------------------------------------------------------------------------------------------
3.Adım: 

/WebContent/WEB-INF/  dosya yoluna serdar-servlet.xml oluşturulmalıdır.

/WEB-INF/serdar-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
        http://www.springframework.org/schema/beans    
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.serdarkocerr.controller" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>

serdar-servlet.xml içerinde bulunan

<context:component-scan base-package="com.serdarkocerr.controller" />

controller'ın nerede aranması gerektigi hakkında bilgi verir. Bizim projemizde com.serdarkocerr.controller package içerisinde controllerın oldugu bilgisi vardır. Handler Mapping'i bu kısım saglar. Bu kısım dikkate alınarak ilgili controller bulunmak için tarama yapılır.

Ayırca bu kısımda View Resolver  tanıtılır. Dönen view bilgisinde view'ın nerede oldugu bilgisi burada belirtilir. Dispatcher Controller bize bir view ismi döner ama uzantısını dönmez. Bu kısımda 


<property name="prefix" value="/WEB-INF/jsp/" />
prefix bilgisi view'ın dosya yolunu verir.

<property name="suffix" value=".jsp" />

suffix bilsi ise gelen view bilgisinin sonuna ne koyarak sayfayı bulacagımızı söyler. Örnegin gelen view bilgisi "welcome" olarak geldi. prefix ( ön-ek ) olarak /WEB-INF/jsp/ koyacagız. Son-ek olarak ise .jsp koyup view ( sayfa) bilgisini elde edecegiz.

/WEB-INF/jsp/welcome.jsp

-----------------------------------------------------------------------------------------------------------------------
4.Adım: 

 /WebContent/WEB-INF/web.xml 'de bulunan web.xml dosyasının  içerigi asagıdaki gibi editlenir. 



/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>SpringMVCHelloWorld</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
    <servlet>
        <servlet-name>serdar</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>serdar</servlet-name>
        <url-pattern>/welcome.html</url-pattern>
    </servlet-mapping>
  
</web-app>


web.xml i inceleyecek olursak,

web.xml sadece ilk proje çalıştırıldıgında hangi sayfanın açılacagını belirtir.


<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>


Ayrıca web.xml de Dispatcher Servlet tanımı yapılmaktadır. Dispatcher servlet konfigürasyon dosyası daha önce belirttigimiz gibi serdar-servlet.xml dosyasıydı. web.xml de ki tanımlamaya dikkat edersek servlet-name serdarolarak verilmiş. Yani serdar-servlet.xml  ismiyle aynı verilmiş.
Bu tanımlama bu şekilde olmalıdır aksi taktirde tanımlanan servlet bulunamaz. 

servlet mapping kısmına dikkat edersek;


    <servlet-mapping>
        <servlet-name>serdar</servlet-name>
        <url-pattern>/welcome.html</url-pattern>
    </servlet-mapping>

şekilinde tanımlanmıştır. Bu kısımda gelen request mesajının URL'inin uzanısına bakarak hangi Dispatcher Servlet'e gidilecegini belirler. Request olarak kullanıcıdan gelen URL

http://localhost:8080/SpringMVCHelloWorld/welcome.html şeklinde ise servlet name de ismi belirtilen servlet çalıştırılır yani serdar-servlet.xml çalıştırılır.


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Detay Bilgi :

 <url-pattern> kısmına birden fazla pattern tanıtılabilir ama Controller'da bu patternlere karşılık bir metod yoksa proje çalıştırılırken Console ekranında WARNING vermektedir. Bu sebepten proje çalışamamaktadır. 
Yani sonuç olarak Controllerda eger karşılıgı yoksa url-patterne ilgili pattern eklenmemelidir.
Örnegin;


    <servlet-mapping>
        <servlet-name>serdar</servlet-name>
        <url-pattern>/welcome.html</url-pattern>
        <url-pattern>/kayit.jsp</url-pattern>
    </servlet-mapping>

şeklinde url-patternler belirtildiyse  Controllerda aşagıdaki gibi olmalıdır. 


@RequestMapping("/welcome")
public ModelAndView helloWorld() {
..... //.....
}

@RequestMapping("/kayit")

public ModelAndView kayit() {


//.....

}

Eger yukarıdaki gibi olmazsa proje run ediliyor ama çalışmıyor.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-----------------------------------------------------------------------------------------------------------------------

5.Adım: 


Java Resources -> src 

sag tıklanır ve New -> Class

ile aşagıdaki gibi bir class oluşturlur.

Package: com.serdarkocerr.controller

FileName : HelloWorld.java

olarak verilir.


com.serdarkocerr.controller.HelloWorld.java
Java
package com.serdarkocerr.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloWorld{
@RequestMapping("/welcome")
public ModelAndView helloWorld() {
String message = "<br><div style='text-align:center;'>"
+ "<h3>********** Hello World, Spring MVC Tutorial</h3>This message is coming from HelloWorld.java **********</div><br><br>";
return new ModelAndView("welcome", "message", message);
}
}



Oluşturulan class'ı incelersek;

@Controller  annotation ile class'ın Controller oldugunu belirtilir.

@RequestMapping("/welcome") annotation ile gelen request mesajının URL'ine 

 bakılır. "/welcome" ile başlayan bütün  URL pathler bu methodta işlem görür. Örnek  verecek 

olursak:

/welcome/* ve/welcome.html URL path'leri bu metodta işlem görür.


helloWorld metdunda işlem bittikten sonra    ModelAndView  tipinde bir nesne return eder. Bu 

nesneyi inceleyecek olursak  ModelAndView("welcome","message",message)  şeklinde nesne 

doldurularak return ediliyor. 

"welcome" olarak belirtilen, return edilen View ismidir.


"message" bir id belirtir. Peki neyin id'sini belirtir derseniz ardından gelen message degiskeninin 

id'sini belirtir. Yani message içeriginde yazan aşagıdaki string'i "message" id ile map ediyoruz.




String message = "<br><div style='text-align:center;'>"
+ "<h3>********** Hello World, Spring MVC Tutorial
</h3>This message is coming from HelloWorld.java **********</div><br><br>";

View'da "message" id ile yukarıda yazan String'i işleyebiliriz.

Sonuç olarak bu class Controller olarak işleve sahiptir. Controller'da Dispatcher Servlete bir ModelAndView nesnesi döner.

Daha sonra da Dispatcher Servlet bu nesneye göre bir View dönecektir.

-----------------------------------------------------------------------------------------------------------------------

6.Adım: 

/WebContent/ altına index.jsp sayfası oluşturuyoruz. web.xml incelenirse başlangıç sayfası olarak index.jsp göstermiştik.



index.jsp
<html>
<head>
<title>serdarkocerr HelloWorld Example </title>
<style type="text/css">
body {
background-image: url('https://crunchify.com/bg.png');
}
</style>
</head>
<body>
<br>
<div style="text-align:center">
<h2>
Hey You..!! This is your 1st Spring MCV Tutorial..<br> <br>
</h2>
<h3>
<a href="welcome.html">Click here to See Welcome Message... </a>(to
check Spring MVC Controller... @RequestMapping("/welcome"))
</h3>
</div>
</body>
</html>


index.jsp başlangıç sayfası olarak açılır.

Başlangıçta açılan sayanın
URL: http://localhost:8080/SpringMVCHelloWorld/


 Sayfa incelendiginde

<a href="welcome.html">Click here to See Welcome Message... </a>

kısmına dikkat edersek, bu kısma tıklanıldıgında URL'in sonuna "welcome.html" eklenecek.

Tıklandıktan sonra oluşan URL: http://localhost:8080/SpringMVCHelloWorld/welcome.html

Bu eklemeden sonra Dispatcher Servlet'e bir request gönderilcek. Spring öncelikle hangi dispatcher servlete gidecegine bakmak için web.xml dosyasına gidecek. web.xml'de, <url-patten> da  aşagıdaki ifadeyi görüp eşleşecek.

<servlet-mapping>
        <servlet-name>serdar</servlet-name>
        <url-pattern>/welcome.html</url-pattern>
    </servlet-mapping>

Eşleştikten sonra serdar isimli servlet'e gidecegini biliyor olacak. serdar isimli servlet için konfigürasyon dosyasına ise serdar-servlet.xml şeklinde gidecek. Bu konfigürasyon dosyasına göre Controller bulup işlemleri gerçekleştirecek.


--------------------------------------------------------------------------------------------------------------------------
7.Adım: 


Controller'dan dönecek olan ModelAndView nesninde belirtilen welcome view'ını oluşturmak için

/WebContent/WEB-INF/jsp/ altına welcome.jsp dosyası yaratılır. 


welcome.jsp
<html>
<head>
<title>Hello World Spring MVC
Example</title>
<style type="text/css">
body {
background-image: url('https://crunchify.com/bg.png');
}
</style>
</head>
<body>
${message}
</body>
</html>


Jsp dosyasını incelersek,


$(message):  ModelAndView nesnesinde message id'ye map edilen ifadeler welcome.jsp sayfasında gösterilecektir.

String message = "<br><div style='text-align:center;'>"
+ "<h3>********** Hello World, Spring MVC Tutorial
</h3>This message is coming from HelloWorld.java **********</div><br><br>";


----------------------------------------------------------------------------------------------------------------------

Son olarak projenin genel görünümü aşagıdaki gibidir.




--------------------------------------------------------------------------------------------------------------

8.Adım: 

Maven projesi derlenmesi ve server'da koşturulması için aşagıdaki adımlar takip edilmelidir.

Projeye sag tıklanıp Run As =>Maven Build 'e tıklanmalıdır.



Açılan pencerede Goals: clean install yazılıp Run edilmelidir.





Run edildikten sonra Console ekranında BUILD SUCCESS yazmalıdır.




Derleme bittikten sonra, projey sag tıklanıp Run As => Run On Server ( Tomcat 8 Seçilmelidir. ) => Finish







Bu işlemlerden sonra Tomcat Server'a proje eklendi ve çalıştırıldı. Çalıştırılırken Console ekranı aşagıdaki gibi olmalıdır. 

Herhangi bir WARNING dikkate alınmalıdır.






Düzgünce çalıştıktan sonra sayfa görüntüleri aşagıdakiler gibi olmalıdır.








Kaynaklar:

https://crunchify.com/simplest-spring-mvc-hello-world-example-tutorial-spring-model-view-controller-tips/