Öncelikle AOP de kullanılan terimleri bir tanıyalım.
Aspect (Bakış açısı)
Birden çok sınıfı kesen bir olayın/özelliğin modülerleştirilmesi. Cacheleme, Loglama, Transaction yönetimi vs. kurumsal Java uygulamalarında kesişen bir olaya/duruma iyi bir örnektir. Spring AOP’de, Aspectler, normal sınıflara, şema tabanlı yaklaşım veya @Aspect annotasyonu kullanılarak uygulanır.
Join point(Bağlantı noktası)
Bir programın yürütülmesi sırasındaki bir noktadır. Bir method yürütülmesi(execute) veya bir istisnanın ele alınması gibi . Spring AOP’de, bir birleştirme noktası her zaman bir method yürütmeyi temsil eder.
Pointcut (Nokta kesimi)
Pointcut ifadesi, bir tür ifade eşleştirme yoluyla birleştirme noktasını tanımlar.
Advice (Tavsiye)
Bu, bir pointcut tarafından seçilen bir joinpointde yürüttüğünüz kod bloğudur. Bu yüzden sistemimizde ortak bir noktaya uyguladığımız cross-cutting concern methodunuzdur.
Target Object (Hedef Nesne)
Bunlar, Advicelerin uygulandığı nesnelerdir. Spring AOP’de, çalışma zamanında hedef methodun geçersiz kılındığı ve yapılandırmalarına göre adviceların dahil edildiği bir alt sınıf oluşturulur.
AOP proxy’si
Spring AOP uygulaması, hedef sınıflar ve advice çağrıları ile Proxy sınıflarını oluşturmak için JDK dinamik proxy kullanır; bunlara AOP proxy sınıfları denir. CGLIB proxy’sini Spring AOP projesinde dependency(bağımlılık) olarak ekleyerek de kullanabiliriz.
Weaving(Dokuma)
Dokuma, advice edilen bir nesne oluşturmak için bir aspect’i diğer uygulama türleri veya nesnelerle ilişkilendirme sürecidir.
Cross-cutting concern nedir?
Cross-cutting concern, bir uygulamada birden çok yerde uygulamak istediğimiz bir durumdur. Tüm uygulamayı etkiler.
AOP (Aspect-Oriented Programming)
Cross-cutting concern konuların ayrılmasına izin vererek modülerliği artıran bir programlama modelidir. Bu cross-cutting concernler, ana iş mantığından farklıdır. Kodun kendisini değiştirmeden mevcut koda ek davranış ekleyebiliriz.
Spring’in AOP çerçevesi, bu cross-cutting concernleri uygulamamıza yardımcı oluyor.
AOP’yi kullanarak ortak işlevleri tek bir yerde tanımlarız. Yeni özelliği uyguladığımız sınıfı değiştirmeden bu işlevin nasıl ve nerede uygulanacağını tanımlamakta özgürüz. cross-cutting concern artık aspect adı verilen özel sınıflara modülerleştirilebilir.
Aspectlerin iki faydası vardır:
İlk olarak, her durumun/olayın mantığını artık kod tabanının her yerine dağılmak yerine tek bir yerde toplamak.
İkincisi, iş modülleri yalnızca birincil concern(durumlar/olaylar) için kod içerir.
Aspectler, Advice adı verilen, uygulanması gereken sorumluluğa sahiptir. Bir aspect’s işlevselliğini bir veya daha fazla birleştirme noktasında(join points) bir programa uygulayabiliriz.
AOP’nin Faydaları
Saf Java ile uygulanır.
Özel bir derleme işlemine gerek yoktur.
Yalnızca method execution Join points(Birleştirme noktalarını) destekler.
Sadece run time weaving(çalışma süresi dokuma) mevcuttur.
İki tür AOP proxy mevcuttur: JDK dinamik proxy ve CGLIB proxy.
AOP Advices Türleri
Before Advice: Bir birleşme noktasından önce yürütülen bir Advice, Adviceden önce çağrılır. Bir Adviceyi Önermeden önce işaretlemek @Before için notunu kullanırız.
After Advice: Bir birleşme noktasından sonra yürütülen bir Advice, Adviceden sonra çağrılır. Bir Adviceyi Adviceden sonra olarak işaretlemek için @After notunu kullanırız.
Around Advice: Bir birleşme noktasından önce ve sonra yürütülen bir Advice.
After Throwing Advice: Bir birleştirme noktası bir istisna oluşturduğunda yürütülen bir Advice.
After Returning Advice: Bir method başarıyla yürütüldüğünde yürütülen bir Advice.
Kavramsal olarak, bir işlem proxy’sinde bir yöntemi çağırmak şuna benzer;
Örnek vermek gerekirse aşağıdaki kod bloğu üzerinde inceleyelim. 2 adet Aspect olayımız var;
1.şu şekilde tanımlı
@Before(value = "execution(* com.thecodemakerz.transaction.service.impl.*Service.*(..))")
bu şu demek “com.thecodemakerz.transaction.service.impl.” bu dizine kadar git ve bundan sonra bu pakette ki sınıflardan sonu Service ile biten tüm sınıfların içindeki tüm methodlar çalıştırılmadan önce;
System.out.println("Before method ASPECT :" + joinPoint.getSignature() + a.toString());
yukarıdaki çıktıyı yaz.
2. ise şu şekilde tanımlı
@After(value = "execution(* com.thecodemakerz.transaction.service.impl.*Service.insert(..))")
bu şu demek “com.thecodemakerz.transaction.service.impl.” bu dizine kadar git ve bundan sonra bu pakette ki sınıflardan sonu Service ile biten tüm sınıfların içindeki insert ile başlayan tüm methodlar çalıştırıldıktan sonra;
System.out.println("After method Aspect:" + joinPoint.getSignature());
yukarıdaki çıktıyı yaz.
Başka bir örnek vermek gerekirse, Controller katmanından Service katmanındaki bir dataya ulaşmadan önce yapılacak aşağıdaki işlemlerin hepsini bu yapı ile gerçekleştirebiliriz;
- Security (Kullanıcı Giriş, Rol, Yetki Kontrolü)
- Validasyon (Gelen data düzgünmü, Ör: TCNo geçerlimi vs.)
- Cahleme
- Loglama
- Performans İzleme
- Execution Time bulma
- Lazy olarak bir entity içinde çalışan bir Many-One ya da One-One vs gibi bir işlemi ihtiyaç anından çağırma gibi
- vs. vs.
Bu gibi durumların en uygun çözümü AOP kullanılmasıdır. Bunu tam anlamak içinde PROXY Design Patterni öğrenmenizi öneririm. Tüm olay o patterni öğrenmede yatıyor.