9 Ağustos 2017 Çarşamba

Spring MVC

Merhaba arkadaşlar,

Bu yazımda Spring MVC yapısını açıklamaya çalışacagım.

Spring java tabanlı enterprise uygulamalar için kapsamlı bir programlama ve konfigürasyon altyapı destegi sunar. Bu sayede yazılımcı birçok yükten kurtulmuş olur.

MVC ise Spring'ten bagımsız olarak WEB projelerinde kullanılan bir yazılım mimarisidir. Spring ile ortaya çıkmamıştır. Hali hazırda bir çok Web projesi için kullanılan ve kabul görmüş bir mimari oldugundan Spring içinde kullanılır.


MVC Mimarisi

Model-View-Controller bir Web mimarisidir. Uygulamanın arayüz, iş-işlem, veri gibi sorumluluklar bakımından katmanlara bölünerek gerçekleştirilmesini saglar. Bu sayede katmanlar birbirinden bagımsızdır ve yönetimi kolaylaşır.

Mimariyi incelersek;

Model:          


  • Uygulamada kullanılan verileri temsil eder ve verilerin işlenme mantığının saklandığı kısımdır.Uygulama verisinden sorumlu katmandır. Gereken nesne tanımları diyebiliriz.
  • Verilerin veritabanına yazılması veya veritabanından alınması burada olabilir.


View:

  • Verilerin arayüzden kullanıcıya sunuldugu katmandır. Basitçe, uygulamamızın kullanıcı tarafından görüldügü arayüzdür. ( jsp vs.)

Controller:

  • Model ve View arasında getir-götür işlemlerini yapar. 
  • Kullanıcı View üzerinden gerçekleştirdigi işlemlerden alınan veriyi Model'e taşır. Model'den aldıgı veriyi ise View üzerinden kullanıcıya gösterir.




Yukarıdaki şekile bakarsak yapıyı daha rahat kafamızda canlandırabiliriz. Kullanıcı tarafından view'dan bir işlem gerçekleştirilir. Öncelikle bu durumda direk Model ile baglantı kurulmaz veya başka bir View ile de baglantı kurulmaz bilgi aktarılmaz. Öncelikle bu bilgilier Controller'a gönderilir. Controller Model ile baglantı kurar ve gerekli işlemleri gerçekleştirip kullanıcıya uygun bilgileri bir View üzerinde gösterir. Controller'ı burada trafik polisi gibi düşünebiliriz. 


Örnek olarak düşünecek olursak,
Bir MVC projesi çalıştırıldıgında kullanıcıya tarayıcı üzerinden bir View gösterilir. Login sayfası örnegini düşünürsek, Login için bir sayfa karşımıza gelir. Bu sayfaya gerekli kullanıcı bilgilerini  ( kullanıcı adı, kullanıcı soyadı, email, şifre vs. ) girdikten sonra KAYIT butonuna bastıgımızda bu bilgiler Controller'a gönderilir. Controller bu bilgileri alıp, bi Model nesnesi oluşturup, nesneye set eder ve daha sonra bu bilgileri Model'e baglı olan database'ye kayıt için gönderir. Database'ye kayıt işleminden sonra Model Controller'a bir cevap döner. Controller'da bu cevaba göre kullanıcıya bir hoşgeldin sayfası ( html , jsp vs) döner. Yani kullanıcıya bir View döner. 

Sonuç olarak Model ile View arasındaki işlemleri Controller'da gerçekleştiririz. Model ile View arasında direk bir baglantı kurulmaz veya iki View arasında da direk bir baglantı kurulmaz. Bütün iş Controller tarafından yönetilir.


Spring MVC Yapısı

MVC mimarisinin Spring yapısına entegre edilmiş şeklidir. Web projelerinin olmazsa olmazıdır.



Yukarıdaki şekilde Spring MVC genel mimarisi gösterilmektedir. Bu yapıyı açıklayacak olursak;

Kullanıcıdan gelen bir istek ( request ) Distpatcher Servlet'e gelir. Dispatcher Servlet  front-controller (design pattern) tasarım deseni yapısında bir dispatcher'dır. Gelen bütün requestler buradan akar ve burada Handle edilerek (Handler Mapping)  doğru controller bilgisi bulunur. Controller bilgisi Disapatcher Servlete'e gönderilir.  Bu bilgiye bakarak Dispatcher Servlet ilgili Controller'a reuqest'i gönderir. İlgili Controller ise gerekli işlemleri yapıp bir ModelAndView nesnesi döndürür. Bu nesne içerisinde hangi View'ın kullanıcıya response olarak gönderilecegi ve View içerisinde gösterilecek bazı bilgiler bulunur. Dispatcher Servlet bu View'ı elde etmek için View Resolver'a gider. View Resolver bir View döndürür ve Dispatcher Servlet ilgili bilgileri bu View içerisine yazar. Ardından View'ı response olarak kullanıcıya gönderir. 

Dispatcher Servlet sadece Spring MVC de kullanılmaktadır.

Spring MVC yapısını daha iyi anlayabilmek için Spring MVC ile Hello World Örnegi yazıma bakabilirsiniz.



Kaynaklar:









Dependency Injection ( DI ) nedir?

Merhaba arkadaşlar,

Bu yazımda Dependency Injection- Bağımlılık Enjeksiyonu kavramını incelyecek ve basit bir örnek üzerinde nasıl uygulandığını açıklayacağım.


Dependency Injection Nedir?


Bağımlılık oluşturan parçaların ayrılıp bunların dışarıdan verilmesiyle sistem içerisindeki birbirine bağımlılığı en aza indirgemektir.

Yani örnek verecek olursak, bir class içerisinde başka bir class nesnesini kullanacaksanız new anahtar kelimesiyle bu nesneyi oluşturmamanızı söyleyen yaklaşımdır. Gereken nesneyi ya Constructor'dan ya da Setter metoduyla parametre olarak alınması gerektiğini söyler. Bu şekilde bir class içerisinde başka bir class'a ait nesneyi new anahtar kelimesiyle yaratmayız ve dışarıdan alırız. Bu bize class'ları birbirinden izole etmemizi sağlar.


Yazılımı oluşturan yapılar ( class'lar vs.) birbirleriyle kaçınılmaz olarak ilişki içerisindedir. Amaç bu ilişkiyi mümkün mertebede gevşek tutmaktır. Buna Loosely Coupled yani Gevşek Bağlılık diyoruz.
Bundan dolayı yapıların birbiriyle olan sıkı bağlarının azalacağı için uygulamaya yeni özellikler ekleyip çıkarmak kolaylaşmaktadır.

Ö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.

Daha sonra günün birinde "B" class'ında bir değişiklik yapma mecburiyeti olduğunda aynı zamanda gidip aynı değişikliği "A" classında da yapmak zorundayız. 1000 tane class "B" classına bağlı ise 1000 classta da gidip değişiklik yapmak zorundayız. Bu büyük projeler için büyük bir iş demektir. Peki bundan kurtulmak için ne yapmalıyız ? Tabikide bağımlılıkları azaltmalıyız ki böyle durumlarla karşılaşmayalım. İşte böyle durumlarda eğer Dependency İnjection tekniği uygularsak minumum değişiklik ile bu işlerden kurtulabiliriz.

Dependency Injection bir Design Pattern'dir.

Dependency Injection Örnek



Dependency Injection iki şekilde uygulanabilir. Yazımızın başlarında bahsettiğmiz gibi bu teknikler;


  • Constructor ile ( Constructor Injection- Constructor Based Dependency Injection )
  • Setter ile ( Setter Injection- Setter Based Dependency Injection )

Javayı az çok bilenlerin aklında şuan nasıl yapılcağı konusu biraz belirmiştir. Yazımızın başında belirttiğimiz gibi bağımlı olunan nesneyi dışarıdan vereceğiz. Bunuda Setter veya Constructor kullanarak yapacağız.

Tabi bunları injecte ederken yani dışarıdan verirken ileride yeni eklenecek durumlarıda göz önünde bulundururak yapacağız.  Yani interface'ler üzerinden bu işi yürütürsek ileride eklenen yeni class'ları injecte ederken herhangi bir zorluk yaşamayız.

Peki nasıl? Örneklerle inceleyelim.




İlk olarak örneğimizde DI uygulamadan yapılmış olanı inceleyelim.


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Araba
{
    public void GazVer()
    {
        //...
    }
    public void FrenYap()
    {
        //...
    }
    public void SagaSinyal()
    {
        //...
    }
    public void SolaSinyal()
    {
        //..
    }
}
public class Vasita
{
    Araba araba;
    public Vasita()
    {
        araba = new Araba();
    }
    public void Kullan()
    {
        araba.GazVer();
        araba.SagaSinyal();
        araba.FrenYap();
        araba.SolaSinyal();
    }
}



Yukarıdaki örnekte Vasita class'ı Araba nesnesine bağlı bir vaziyettedir. Bu durumda Vasita nesnesi üretilirken "Araba" nesneside üretilmelidirki bu nesneye ait özellikler "Kullan" metodunda kullanılabilinsin. İleride bir gün "Araba" class'ı içerisnde bir değişiklik yaptığımızda gelip "Vaista" class'ında da değişiklik yapmamız gerekebilir. Bu gibi 100 tane class düşünürsek işimiz hayli uzun oluyor.

"Vasita" class'ına bir gün "Araba" değilde "Otobüs" nesnesi geçmek istersek, "Vasita" class'ı içine gelip "Kullan" metodunun içerisindeki komutları güncellemem gerekebilir.

Şimdi öyle bişey yapalım ki "Vasita" nesnesi hem "Araba" hemde "Otobüs" nesenesini kullanabilsin ve bundan haberi olmasın. Hatta ileride "Motor" nesnesi diye bir ihtiyaç doğarsa bunuda karşılayabilsin.

Peki nasıl olacak?


Dependency Injection design patternini uygulamak için öncelikler bir interface tanımlamamız gerekmektedir. Tanımlayacağımız bu interfaceyi tüm class'lar implement edecek ve parametre olarak bu interface kalıbını kabul eden constructor ve setter metoduna class'ı gönderebileceğiz.


1
2
3
4
5
6
7
public interface ITasit
{
    void GazVer();
    void FrenYap();
    void SagaSinyal();
    void SolaSinyal();
}


Oluşturduğumuz ITasit interfacesinden "Araba", "Otobüs", "Motor" vs. taşıtları bu interfaceten türeteceğiz.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class Araba implements ITasit
{
    public void GazVer()
    {
        //...
    }
    public void FrenYap()
    {
        //...
    }
    public void SagaSinyal()
    {
        //...
    }
    public void SolaSinyal()
    {
        //..
    }
}
public class Otobus implements ITasit
{
    public void GazVer()
    {
        //...
    }
    public void FrenYap()
    {
        //...
    }
    public void SagaSinyal()
    {
        //...
    }
    public void SolaSinyal()
    {
        //..
    }
}
public class Motor implements ITasit
{
    public void GazVer()
    {
        //...
    }
    public void FrenYap()
    {
        //...
    }
    public void SagaSinyal()
    {
        //...
    }
    public void SolaSinyal()
    {
        //..
    }
}


Bu şekilde ilgili class'ları ITasit interfacesiyle  türettik.

Şimdi Dependency Injection uygulamaya sıra geldi.

Yazımızın başında 2 şekilde uygulayabileceğimizden bahsetmiştim. Bunları teker teker inceleyeceğiz.

Constructor Injection

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
class public Vasita
{
    ITasit _tasit;
    public Vasita(ITasit tasit)
    {
        _tasit = tasit;
    }
    public void Kullan()
    {
        _tasit.GazVer();
        _tasit.SagaSinyal();
        _tasit.FrenYap();
        _tasit.SolaSinyal();
    }
}


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
class public Program
{
    public static void main(string[] args)
    {
ITasit araba = new Araba();
        Vasita vasitaAraba = new Vasita(araba);
        vasitaAraba.Kullan();
        

ITasit otobus= new Otobus();
        Vasita vasitaOtobus = new Vasita(otobus);
        vasitaOtobus.Kullan();
        

ITasit motor= new Motor();
        Vasita vasitaMotor = new Vasita(motor);
        vasitaMotor.Kullan();
    }
}

Yukarıdaki kodu incelersek, "Vasita" class'ı içerinde ITasit interface'si tipinde bir nesne declare ediliyor. Ardından constructor içerisinde ITasit interfacesi tipinde bir nesneye eşitleniyor. Yani "Vasita" sınıfına ITasit interface tipinde bir nesne gerekiyor. Yukarıda bakıldığında "Araba", "Otobüs", "Motor" classları "ITasit" interfacesini implement ettiği için eğer bu class'lardan bir nesne üretilirse "Vasita" sınıfına bu nesneler gönderilebilir. Yani bu haliyle "Vasita" sınıfına isterseniz "Araba", isterseniz "Otobüs" isterseniz de "Motor" nesnesi üretip verebilirsiniz. ( Bu nesneler "ITasit" interfacesini implement etmek zorunda ( Polimorfizm kuralı gereği)) 

Olaya "Vasita" sınıfı tarafından bakarsak, "Vasita" sınıfı kendine verilen nesnenin ne  olduğu ile ilgilenmiyor. Sadece "ITasit" interfacesine cast yapabilir mi diye bakıyor. Yani gelen nesenenin interface de tanımlı metodları "Vasita" sınıfını ilgilendiriyor. İçeriğinin ne olduğuyla ilglenmiyor. Mesela GazVer() metodu "Motor" nesnesi için kolu çevirmek iken, "Otobus" nesnesi için pedala basmak ama "Vasita" sınıfı sadece GazVer() metoduyla ilgileniyor içeriğiyle değil.

Bu sayede "Vasita" sınıfının farklı sınıflara bağımlılığı azalıyor.


Setter Injection

Detaylar yukarıda bahsettiğimin aynısı. Sadece uygulanış biçimi set fonksiyonu üzerinden olacak.


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
public class Vasita
{
    public ITasit tasit;

 public void setTasit(ITasit tasit)
{ this.tasit = tasit; }

    public void Kullan()
    {
        tasit.GazVer();
        tasit.SagaSinyal();
        tasit.FrenYap();
        tasit.SolaSinyal();
    }
}

Setter Injection yöntemi için kullanımı aşağıdaki gibi yapmalısınız.



01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Program
{
    public static void main(string[] args)
    {
ITasit araba = new Araba();
Vasita vasitaAraba = new Vasita();
vasitaAraba.setTasit(araba ); vasitaAraba.Kullan();

ITasit otobus= new Otobus();
Vasita vasitaOtobus = new Vasita(); vasitaOtobus.setTasit(otobus); vasitaOtobus.Kullan();


ITasit motor= new Motor(); Vasita vasitaMotor = new Vasita(); vasitaMotor.setTasit(motor); vasitaMotor.Kullan();

    }
}


Görüldüğü üzere Dependency Injection kodda bağımlılığı azaltıp, ileride eklenecek özellikler için rahatlık sağlamaktadır.



Detay:
Bu özellik aslında Polimorfizm ile sağlanır. Yani bir class bir interfaceyi implement eder. Bu class'ı implemet ettiği interface tipinde casting yapabiliriz. Bu sayede ilgili constructor veya setter metoduna interface yerine bu class'ı gönderebiliriz.



Kaynakar:

http://www.gencayyildiz.com/blog/dependency-injection-nedir-nasil-uygulanir/

http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/