Skip to content

Latest commit

 

History

History
930 lines (785 loc) · 46.3 KB

chapter-07.asc

File metadata and controls

930 lines (785 loc) · 46.3 KB

Aspect Yapısı

AspectJ dilinin bize kazandırdığı son crosscutting ünitesi aspect (ilgi) birimi, AOP yaklaşımını istenilen sisteme uygulamamız için kullanmamız gereken ilk yapıdır. Aspect birimleri içerisinde tanımlanan sistemin davranışını ve yapısını değiştirecek crosscutting özelliklere sahip bileşenler — pointcut, tavsiye, ara tip tanımlama gibi — , AspectJ Weaver tarafından alınıp AOP yaklaşımı için sistemin yeniden düzenlenmesini sağlamaktadır. Aspect yapıları aynı zamanda özel bileşenleri bünyesinde barındırdığı için ilgileri sarmalayan bir yapıya da sahiptir. İlgi modülü/birimi/ünitesi sınıf tanımlamasına çok benzediği gibi farklılıklar ile de yeni özellikler bize sunmaktadır. Bu yapının tanımı sınıf tanımlamasına benzediği gibi farklılıklara da sahiptir.

İlgi Birimi Anatomisi:
    [privileged] [erişim belirleyici] [abstract] aspect <AspectName>
    [extends Sınıf ya da Soyut İlgi] [implements arayüz(ler)]
    [
     [issingleton()] ya da
     [<perthis | pertarget | percflow | percflowbelow>(Pointcut)] ya da
     [pertypewithin(Tip İmza Deseni)]
    ] {
        // ilgi gövdesi
        AfterAdviceDeclaration
        AfterThrowingAdviceDeclaration
        AfterReturningAdviceDeclaration
        BeforeAdviceDeclaration
        PointcutDeclaration
        //... diğerleri (Java elementleri dahil)
    }

En basit aspect tanımlaması sınıf tanımlaması gibi şu şekildedir:

aspect LoggingAspect {
    // aspect body
}

En karışık aspect tanımlaması sınıf tanımlaması ile karşılaştırıldığında şu şekilde olabilir:

privileged public aspect LoggingAspect
           extends AbstractAspect implements Advisable pertypewithin(Account+) {
        // aspect body
}

İlgi yapısı aspect anahtar kelimesi ile tanımlanmaktadır. Her ilgi birimi:

  1. Erişim belirleyicisine sahip olabilir.

  2. abstract yapısında tanımlanabilir.

  3. extends ve implements yollarıyla diğer modüllere erişebilir.

  4. Farklı ilgi ilişkilendirmeleriyle yeni özelliklere sahip olabilir (ör. pertarget(<Pointcut>)).

  5. Kendi bünyesinde statik crosscutting, dinamik crosscutting yapılarını, pointcut, intertype tanımlamaları, metod, alan ve nested tip tanımlamaları yapılabilir.

Aspect vs Class

Sınıf yapısı içerisinde nasıl OOP kullanarak yaptığımız tasarımı somut olarak ön plana çıkarıyorsak, İlgi yapısında da AOP (bileşenlerini) kullandığımız gibi sistemin gereksinimine göre de OOP’den de yararlanarak enine kesen ilgi eylemlerinin programlanmasını ortaya çıkarmaktayız. İlgi birimleri sınıf birimlerine göre biraz daha sorumluluk sahibidirler. Sınıf içerisinde ihtiyaç duyulan ve programlanan her bir düşünceyi, ilgi birimlerinin içerisinde de yapmak mümkündür.

Aspect ve Sınıf arasındaki ortak özellikler
  1. public, abstract ve ya final belirleyiciye sahip olabililr. Nested ilgiler ise public, private, protected ya da paket (default) erişime sahip olurlar.

  2. Birimler içerisinde geleneksel Java elementlerinden alan ve metod tanımlamaları yapılabilir.

  3. abstract birim olarak nitelendirilebilirler. Soyut ilgi birimleri yaratılarak içlerinde pointcut ve metodların da abstract olarak tanımlanabilinmesine izin verilmektedir.

  4. implements ve extends yaparak diğer birimlere — sınıf, arayüz(ler) — bağlanabilirler. Bir ilgi birimi sınıf aracılığla türeyebildiği gibi sadece ama sadece soyut ilgi’den gelişebilir.

  5. Bir ilgi başka bir ilginin, sınıfın, ya da arayüzün içerisinde yaratılabilir. Gömülü ilgiler (nested aspects) static olarak tanımlanmalıdır.

Important
İlgi birimleri .aj uzantılı dosyalarda oluşturulmaktadır. Bu dosyalarda ilgi haricinde arayüzler ve sınıflar da tanımlanabilir. Dolayısıyla ilgilerin gömülü olarak başka tip içerisinde oluşturulmasına da izin verilmektedir.
Aspect ve Sınıf arasındaki farklılıklar
  • İlgileri sınıflar gibi new anahtar kelimesi ile nesnesini oluşturamayız.

  • İlgiler (overloaded) yapıcı tanımlamalarını desteklememektedir. İlgi birimlerinin içerisinde sadece parametresiz varsayılan yapıcı tanımlanabilir.

  • Bir ilgi sadece soyut ilgiden türeyebildiği gibi soyut/somut sınıflardan da gelişebilir.

  • privileged özelliği ile ilgiler tavsiyeden etkilenen sınıfların private olan nesne değişkenlerine ve metodlarına ulaşabilir.

Aspect Instantiation

Daha önce de bahsedildiği gibi ilgi birimlerinin new kelimesi ile nesnesini yani örneğini alamayız. İlgi birimleri sistemde varsayılan olarak global bir yapıya sahiptir. Sistemde tek bir örneğe sahip olan bir global ilgi birimi aynı zamanda singleton davranışına da sahip olur. Farklı ilgi ihtiyaçları ve onların doğurduğu değişik sistem gereksinimlerine göre bir ilgi birimi farklı birleşim noktalarına özel olarak sistemde birden fazla örneklenebilir. Yani bir sistemde sadece tek örneğe sahip bir ilgi çalışırken başka bir sistemde bir ilgi ve onunla çalışan bileşenler, birleşim noktalarının sayısına göre örneklenebilir. Diğer bir deyişle, sistemin çalışma akışında örnekleme (instantiation) yapıları yardımıyla bir ilgi tavsiye alacak birleşim noktaların özelliğine göre birden fazla örneği çalışabilir.

İlgilerin örneklenebilme davranışını aspect tanımlaması içerisinde yapmaktayız. Başlıca örnekleme yapıları:

  1. issingleton()

  2. perthis(Pointcut)

  3. pertarget(Pointcut)

  4. percflow(Pointcut)

  5. percflowbelow(Pointcut)

  6. pertypewithin(Tip İmza Deseni)

Singleton Yapısı

Yaratılan aspect yapıların varsayılan özelliği her zaman singleton davranışına sahiptir. Eğer bir ilgi birimi hiç bir örnekleme yapısı barındırmıyorsa bu ilgi direkt olarak global yani singleton tanımlanır tüm sistem için.

Varsayılan ilgi birimi:
public aspect Logging issingleton(){ (1)
    // aspect body
}

public aspect Logging {              (2)
    // aspect body
}
  1. (2) ile aynı özelliğe sahiptir. Tüm sistemde sadece bu ilgi (örnek) çalışır. Bu ilgiden birden fazla örnekleme sistemin akışında oluşmaz.

  2. (1) ile aynı özelliğe sahiptir. Global olarak tek bir örneği çalışır tüm sisteme bağlandığında.

Örnek 1) Global ilgi örneği:
package com.kodcu.concerns.core;
public class Library {
    public void doSomething(){}
    public boolean isOkay(){return true;}
    public void doNothing(){}
}

package com.kodcu.concerns.aspects;
import com.kodcu.concerns.core.Library;
public aspect TraceAspect {
    /* Constructor */
    public TraceAspect() {
    	System.out.println("Creating TraceAspect instance");
    }
    pointcut doTrace(Library lib) :
                    call(* *(..)) &&
                    within(com.kodcu.tests.Test) &&
                    target(lib);

    after(Library lib) :doTrace(lib){
        System.out.println("Join Point: " + thisJoinPointStaticPart
        		 + "Aspect: " + this
        		 + "Object: " + lib);
    }
}

package com.kodcu.tests;
import com.kodcu.concerns.core.Library;
public class Test {

    public static void main(String[] args) {
        Library library = new Library();
>>      library.doNothing();
>>      library.doSomething();
        Library library2 = new Library();
>>      library2.isOkay();
    }
}
Çıkan Sonuç:
Creating TraceAspect instance                                    (1)
Join Point: call(void com.kodcu.concerns.core.Library.doNothing())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7           (2)
	Object: com.kodcu.concerns.core.Library@9ee92                   (3)
Join Point: call(void com.kodcu.concerns.core.Library.doSomething())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
	Object: com.kodcu.concerns.core.Library@9ee92
Join Point: call(boolean com.kodcu.concerns.core.Library.isOkay())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
	Object: com.kodcu.concerns.core.Library@f39991                  (4)
  1. Global davranışında olan TraceAspect ilgisi bir kere örneklenir ve 3 metod çağırma birleşim noktasında da bu örneğe ait bileşenler çalışır.

  2. Tavsiye içinde kullanılan this özelliği ile ilgi örneğinin yani nesnesinin adresini görmüş oluyoruz.

  3. Library sınıfından oluşturulan library nesnesinin değerini görmekteyiz.

  4. Library sınıfından yaratılan diğer bir örneğin (library2) değeri gösterilmektedir. İlgi birimi sistemde tek örneğe sahip sabit ve değişmiyor.

İlginin yapısı global olduğu için çalışma zamanında tek bir örneğe sahip olmaktadır. Arka tarafta bizim göremediğimiz ama aslında olan işlemler sırasıyla:

Örnek 2) Global ilginin arka planda oluşumu:
...
... Örnek 1 deki değişmeyen kod parçaları
...

package com.kodcu.concerns.aspects;
import com.kodcu.concerns.core.Library;
public aspect TraceAspect {
   private static TraceAspect instance = null;

   public static TraceAspect getSingleton() {
      if(instance == null) {
         instance = new TraceAspect();
      }
      return instance;
   }
   ...
   ... değişmeyen diğer üniteler
}

package com.kodcu.tests;
import com.kodcu.concerns.core.Library;
public class Test {

    public static void main(String[] args) {
     TraceAspect aspectinstance = TraceAspect.getSingleton();                  (1)
     Library library = new Library();
     try{
>>      library.doNothing();
     }
     finally{
      aspectinstance.ajc$after_com_kodcu_concerns_aspects_$1$01231412(library);(2)
     }
     try{
>>      library.doSomething();
     }
     finally{
      aspectinstance.ajc$after_com_kodcu_concerns_aspects_$1$01231412(library);(3)
     }
     Library library2 = new Library();
     try{
>>      library2.isOkay();
     }
     finally{
      aspectinstance.ajc$after_com_kodcu_concerns_aspects_$1$01231412(library2);(4)
     }
    }
}
  1. main metodun içerisinde birleşim noktaları mevcut olduğu için program çalışmaya başladıktan sonra bir TraceAspect ilgi biriminin nesnesi/örneği oluşmamışsa oluşturulur.

  2. Eşlenen noktadan sonra çalışması istenen bir Library sınıfı tipinde parametre alan tavsiye yapısı finally bloğuna konuşlanmaktadır.

  3. (2) de olduğu gibi doSomething metodunun çağırılma sonrası gene aynı ilgiye ait nesneden after tavsiye yapısına gidilmektedir.

  4. Sistemin son basamağında isOkay metodunun çağırılmasından sonra tavsiye bileşeni, parametrede yeni yaratılan library2 nesnesini referans almaktadır.

Perthis Yapısı

Nesne tabanlı örnekleme yapısından biri olan perthis içerisinde tanımlanan pointcut ile seçilen birleşim noktalarında tipin nesnesine göre ayrı ilgi örneği oluşturulmasını sağlamaktadır. Seçilen birleşim noktalarında nesnenin tipi ile perthis içerisinde belirtilen tipin aynı olması gerekmektedir böylelikle tipin nesnesinin farklılığına göre seçilen birleşim noktalarında yeni ilginin örneğinin meydana gelmesi sağlanır.

Örnek 3) 'perthis' kullanımı:
package com.kodcu.concerns.aspects;
import com.kodcu.concerns.core.Library;
public aspect TraceAspect perthis(doTrace(Library)) {           (1)
	/* Constructor */
    public TraceAspect() {
    	System.out.println("Creating TraceAspect instance");
    }
    pointcut doTrace(Library lib) :                             (2)
                    call(* *(..)) &&
                    this(lib);
    after(Library lib) :doTrace(lib){
        System.out.println("Join Point: " + thisJoinPointStaticPart
        		 + "Aspect: " + this
        		 + "Object: " + lib);
    }
}

package com.kodcu.concerns.core;
public class Library {
    public void doSomething(){
>>      this.doNothing();                   (3)
    }
    public boolean isOkay(){return true;}
    public void doNothing(){
>>      this.isOkay();                      (4)
    }
}


package com.kodcu.tests;
import com.kodcu.concerns.core.Library;
public class Test {
    public static void main(String[] args) {
        Library library = new Library();
        library.isOkay();
        library.doSomething();
        Library anotherlibrary = new Library();
        anotherlibrary.doNothing();
        Library millikutuphane = new Library();
        millikutuphane.isOkay();
    }
}
  1. Library nesnesi doğrultusunda Library sınıfının içinde belirlenen birleşim noktalarında yeni TraceAspect örnekleri yaratılır. perthis içindeki pointcut tanımlaması aynı zamanda şu şekilde de yazılabilir: perthis(within(Library))

  2. Eminimki buraya kadar bölümleri atlamadan gelen okuyucular artık bu isimlendirilen pointcut yapısının ne anlattığını çok rahat bir şekilde söyleyebilir.

  3. Seçilen birleşim noktaları doğrultusunda bu satırda tipin nesnesine bakılarak TraceAspect ilgisinden yeni bir örnek türetilir.

  4. (3). satırdaki özellikler ile aynıdır. Eğer sistemin akışında bu noktadan geçilirse tipin nesne farklılığına göre yeni bir ilgi örneği yaratılır ve tavsiye çalışır.

Perthis Sonucu:
Creating TraceAspect instance                                       (1)
Join Point: call(boolean com.kodcu.concerns.core.Library.isOkay())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
	Object: com.kodcu.concerns.core.Library@9ee92
Join Point: call(void com.kodcu.concerns.core.Library.doNothing())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
	Object: com.kodcu.concerns.core.Library@9ee92
Creating TraceAspect instance                                       (2)
Join Point: call(boolean com.kodcu.concerns.core.Library.isOkay())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@f39991
	Object: com.kodcu.concerns.core.Library@12b3a41
  1. Sistemin çalışma akışında görüyoruzki main metod içinde çağırılan doSomething metodunun içine girilip library nesnesi için ilgi örneği oluşturulmaktadır çünkü doSomething metodunun içerisinde potansiyel birleşim noktası mevcuttur (Örnek 3, 3.satır).

  2. Yeni bir ilginin örneği main metod içinde çağırılan doNothing metodunun içerisinde meydana gelir. Nedeni; bu metodun içindeki birleşim noktasının tetiklenmesi ve en önemlisi sistemin akışında tipin nesnesi bu sefer anotherlibrary için oluşudur. Dolayısıyla, this.isOkay(); noktasında yeni ilgi tanımlanır ve tavsiye yapısı çalışır. Sistemin çalışması süresince bir tane daha Library sınıfına ait örnekleme (millikutuphane) oluşturuluyor fakat bu nesne için başka bir ilgi yaratılmıyor çünkü isOkay metodu çağırıldıktan sonra metodun içinde hiç bir birleşim noktasına rastlanmıyor.

Pertarget Yapısı

Diğer bir nesne tabanlı örnekleme yapısı pertarget, hedef nesne ile ayrı bir ilgi örneğine birleşir. Seçilen birleşim noktalarında hedef nesnenin tipi ile pertarget içerisinde belirtilen tipin aynı olması gerekmektedir böylelikle tipin nesnesine bakılarak seçilen birleşim noktalarında yeni ilginin örneğinin meydana gelmesi sağlanabilir.

Örnek 4)
package com.kodcu.concerns.core;
public class Library {
    public void doSomething(){this.doNothing();}
    public boolean isOkay(){return true;}
    public void doNothing(){this.isOkay();}
}


package com.kodcu.concerns.aspects;
import com.kodcu.concerns.core.Library;
public aspect TraceAspect pertarget(doTrace(Library)) {           (1)
	/* Constructor */
    public TraceAspect() {
    	System.out.println("Creating TraceAspect instance");
    }
    pointcut doTrace(Library lib) :                               (2)
                    call(* *(..)) &&
                    target(lib) &&
                    within(com.kodcu.tests.Test);
    after(Library lib) :doTrace(lib){
        System.out.println("Join Point: " + thisJoinPointStaticPart
             + "Aspect: " + this
             + "Object: " + lib);
    }
}



package com.kodcu.tests;
import com.kodcu.concerns.core.Library;
public class Test {
    public static void main(String[] args) {
        Library milliKutuphane = new Library();
>>      milliKutuphane.doSomething();                   (3)
>>      milliKutuphane.doNothing();                     (4)
        Library izmirMilliKutuphane = new Library();
>>      izmirMilliKutuphane.doNothing();                (5)
        Library kent = new Library();
>>      kent.isOkay();                                  (6)

        Runnable ru = () -> System.out.println("*");
        ru.run();                                       (7)
        Store store = new Store();
        store.getStoreID();                             (8)
    }
}
Pertarget Çıktısı:
Creating TraceAspect instance
Join Point: call(void com.kodcu.concerns.core.Library.doSomething()) //satır 3
	Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
	Object: com.kodcu.concerns.core.Library@9ee92
Join Point: call(void com.kodcu.concerns.core.Library.doNothing())  //satır 4
	Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
	Object: com.kodcu.concerns.core.Library@9ee92
Creating TraceAspect instance
Join Point: call(void com.kodcu.concerns.core.Library.doNothing())  //satır 5
	Aspect: com.kodcu.concerns.aspects.TraceAspect@f39991
	Object: com.kodcu.concerns.core.Library@12b3a41
Creating TraceAspect instance
Join Point: call(boolean com.kodcu.concerns.core.Library.isOkay()) //satır 6
	Aspect: com.kodcu.concerns.aspects.TraceAspect@574795
	Object: com.kodcu.concerns.core.Library@16f4d33
*
  1. Library sınıfının nesnesi hedef alınarak doTrace içerisinde sağlanan şartlara uyan noktalarda yeni TraceAspect ilgisinin örnekleri oluşturulur.

  2. Sistemde Test sınıfının içerisinde, hedef nesnenin tipi Library olduğu her bir metod çağırma noktasını belirler. Bunun yanında, örnekleme işleminin gerçekleşmesi için birleşim noktalarındaki nesne ilişkisinin de farklı olması gerekmektedir. >> sembolü metod çağırma birleşim noktalarının gölgelerini gösterdiği gibi aynı zamanda potansiyel ilgi örneklemelerinin de gerçekleşeceği noktaları işaret etmektedir.

  3. Library sınıfının nesnesine, millikutuphane, ait olan doSomething metodunun çağırılmasında ilk ilgi örneği tanımlanmış olmaktadır ve gerekli tavsiye çalışır.

  4. (3). satırı takiben, millikutuphane nesnesi ile çağırılan doNothing metodu ile aynı ilgi örneği çalışmaktadır. Yeni ilgi örneği yaratılmıyor çünkü mevcut olan aynı nesne ile devam edilmektedir.

  5. Library sınıfının bir diğer yeni nesnesi izmirMilliKutuphane ile yeni bir ilginin oluşturulur ve doNothing metodu çağırıldıktan sonra gerekli tavsiye yapısı çalışır.

  6. Aynı şekilde diğer bir Library nesnesinin oluşumu (kent) sonrası başka bir TraceAspect ilgisinin nesnesi oluşturulur ve isOkay motodunun çağırılmasından sonra tavsiye tetiklenir.

  7. Runabble sınıfının çalışmasını sağlayan run metodu bu kriterlere uymadığı için sadece program akışında gerekli olan görevini yerine getirir.

  8. (7) gibi belirtilen Library tipine ait olmayan başka sınıf tarafından tanımlanan bir nesne ve bu nesneye ait bir metodun çağırılması birleşim noktası olarak belirtilmemektedir. Eğer Store sınıfı Library sınıfından türeseydi store.getStoreID(); noktasında yeni bir ilginin daha örneği oluşurdu.

Percflow Yapısı

percflow, içerisinde bağlanan her bir birleşim noktası ve onların kontrol akışında aynı pointcut kriterlerine uyanlarla eşlenen noktalar için ilgi birimi örneklenmesini sunmaktadır. Cflow yapısına göz atmak isteyenler Control-Flow Tabanlı yapılara tekrar bakabilir.

Örnek 4) Bir 'percflow' özelliğine sahip TraceAspect ilgisi:
package com.kodcu.concerns.core;
public class Library {
    public void doSomething(){
>>      this.doNothing();
    }
    public boolean isOkay(){return true;}
    public void doNothing(){
>>      this.isOkay();
    }
    public void doWhat(){ }
}




package com.kodcu.concerns.aspects;
import com.kodcu.concerns.core.Library;
public aspect TraceAspect percflow(doTrace(Library)) {           (1)
	/* Constructor */
    public TraceAspect() {
    	System.out.println("Creating TraceAspect instance");
    }
    pointcut doTrace(Library lib) :
                    call(* *(..)) &&
                    target(lib);
    after(Library lib) :doTrace(lib){
        System.out.println("Join Point: " + thisJoinPointStaticPart
             + "Aspect: " + this
             + "Object: " + lib);
    }
}

package com.kodcu.tests;
import com.kodcu.concerns.core.Library;
public class Test {
    public static void main(String[] args) {
        Library halkKutuphane = new Library();
>>      halkKutuphane.doSomething();                (2)
>>      halkKutuphane.doNothing();                  (3)
        Library kent = new Library();
>>      kent.doWhat();                              (4)
        Library milliKutuphane = new Library();
>>      milliKutuphane.isOkay();                    (5)

        Runnable ru = () -> System.out.println("**");
        ru.run();

        Store store = new Store();
        store.getStoreID();
    }
}
percflow Çıktısı:
Creating TraceAspect instance
Join Point: call(boolean com.kodcu.concerns.core.Library.isOkay())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@1b54208
	Object: com.kodcu.concerns.core.Library@1e6f5c3
Creating TraceAspect instance
Join Point: call(void com.kodcu.concerns.core.Library.doNothing())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@1884d57
	Object: com.kodcu.concerns.core.Library@1e6f5c3
Creating TraceAspect instance
Join Point: call(void com.kodcu.concerns.core.Library.doSomething())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@af3868
	Object: com.kodcu.concerns.core.Library@1e6f5c3
Creating TraceAspect instance
Join Point: call(boolean com.kodcu.concerns.core.Library.isOkay())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@1459877
	Object: com.kodcu.concerns.core.Library@1e6f5c3
Creating TraceAspect instance
Join Point: call(void com.kodcu.concerns.core.Library.doNothing())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@12133b1
	Object: com.kodcu.concerns.core.Library@1e6f5c3
Creating TraceAspect instance
Join Point: call(void com.kodcu.concerns.core.Library.doWhat())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@ea2f77
	Object: com.kodcu.concerns.core.Library@1c7353a
Creating TraceAspect instance
Join Point: call(boolean com.kodcu.concerns.core.Library.isOkay())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@1a9515
	Object: com.kodcu.concerns.core.Library@f49f1c
**
  1. percflow, Library nesnesine ait olan her bir metod çağırma noktalarının ve onların kontrol akışında gene aynı Library nesnesine ait her bir metod çağırma noktasında TraceAspect ilgisinin örneğinin yaratılmasını sağlamaktadır. Tipin nesnesine bakılmaksızın her birleşim noktasında bir ilgi biriminin nesnesi yaratılır.

  2. doSomething metodu ilk birleşim noktası olmaktadır. Bu nokta ve içerisindeki Library nesnesine ait metod çağırmalarda birer ilgi örneği yaratılır. Bu metodun kontrol akışı izlenirse: isOkaydoNothingdoSomething metodları çalışır ve bu noktalarda yeni ilgiler yaratılır.

  3. doNothing metodunun çağırılması ve kontrol akışında içeriğinde uyan diğer birleşim noktalarında yeni TraceAspect nesnesi oluşmaktadır. Ilk isOkay metodunun çağırımdan oluşan örnekleme gerçekleşir ve daha sonra doNothing metodunun çağırılmasıyla başka bir örnekleme meydana gelmektedir (TraceAspect@1459877TraceAspect@12133b1)

  4. Library sınıfının yeni bir nesnesi, kent , ile çağırılan doWhat metodu noktasında, TraceAspect@ea2f77 bilgisine sahip yeni örnekleme gerçekleşmektedir.

  5. Sistemde pointcut yapısına uyan ve eşlenen nokta milliKutuphane nesnesiyle çağırılan isOkay metodu olmaktadır. Bu metod noktasında da ilgi birimi tekrar yeni bir örneğine sahiptir.

Percflowbelow Yapısı

percflowbelow, içerisinde bağlanan her bir birleşim noktası hariç tutularak sadece onların kontrol akışında aynı pointcut kriterlerine uyanlarla eşlenen noktalar için tavsiye yordamları çalışmaktadır. percflow yapısında olduğu gibi gene her birleşim noktasında istenen ilgi biriminin örneği yapılmaktadır ama percflowbelow yapısının çalışma şeklinin farklılığından dolayı sadece kontrol akışında mevcut olan noktalarda belli çıktılar görebiliyoruz çünkü tavsiye yapıları o noktalarda devreye girmektedir. Cflowbelow yapısına göz atmak isteyenler Control-Flow Tabanlı yapılara tekrar bakabilir.

Örnek 5) Bir 'percflowbelow' özelliğine sahip TraceAspect ilgisi:
package com.kodcu.concerns.core;
public class Library {
    public void doSomething(){
<<      this.doNothing();
    }
    public boolean isOkay(){	return true;	}
    public void doNothing(){
<<      this.isOkay();
    }
    public void doWhat(){ }
}



package com.kodcu.concerns.aspects;
import com.kodcu.concerns.core.Library;
public aspect TraceAspect percflowbelow(doTrace(Library)) {           (1)
	/* Constructor */
    public TraceAspect() {
    	System.out.println("Creating TraceAspect instance");
    }
    pointcut doTrace(Library lib) :
                    call(* *(..)) &&
                    target(lib);
    after(Library lib) :doTrace(lib){
        System.out.println("Join Point: " + thisJoinPointStaticPart
             + "Aspect: " + this
             + "Object: " + lib);
    }
}



package com.kodcu.tests;
import com.kodcu.concerns.core.Library;
public class Test {
    public static void main(String[] args) {
        Library milliKutuphane = new Library();
>>      milliKutuphane.doSomething();
>>      milliKutuphane.doNothing();
        Library kentKutuphane = new Library();
>>      kentKutuphane.doWhat();
        Library halkKutuphane = new Library();
>>      halkKutuphane.isOkay();
        Runnable ru = () -> System.out.println("**");
        ru.run();
        Store store = new Store();
        store.getStoreID();
    }
}
  1. percflow dan farklı olarak, artık biliyoruzki percflowbelow içinde pointcut yapsı ile belirlenen noktalarda tavsiye yordamları çalışmamaktadır. Dolayısıyla percflowbelow yapısı ile sistem çıktısında bu birleşim noktaları hakkında bilgi sahibi olamamaktayız ama unutmamamız gereken şu ki her noktada birer ilgi örneği gene oluşturulmaktadır. Her ne kadar >> ile gösterilen yerler birer birleşim nokta gölgesi olsa da, bu gölgeler içerisinde gerçekleşen birleşim noktalarında istenilen bilgiler elde edilir (<< ile gösterilen birleşim nokta gölgelerinde tavsiye yapılarının yani enine kesen eylemlerin çalıştığı noktalardır).

percflowbelow Çıktısı:
Creating TraceAspect instance                                       (1)
Creating TraceAspect instance
Join Point: call(boolean com.kodcu.concerns.core.Library.isOkay())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@1b54208
	Object: com.kodcu.concerns.core.Library@1e6f5c3
Creating TraceAspect instance
Join Point: call(void com.kodcu.concerns.core.Library.doNothing())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@1884d57
	Object: com.kodcu.concerns.core.Library@1e6f5c3
Creating TraceAspect instance
Join Point: call(boolean com.kodcu.concerns.core.Library.isOkay())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@af3868
	Object: com.kodcu.concerns.core.Library@1e6f5c3
Creating TraceAspect instance                                       (2)
Creating TraceAspect instance                                       (3)
Creating TraceAspect instance                                       (4)
  1. main metod içerisinde doSomething metodunun çağırılması bir birleşim noktası olarak seçildiği için bu noktada yeni bir ilgi nesnesi yaratılır ama tavsiye çalışmaz.

  2. main metod içerisinde doNothing metodunun çağırılması bir birleşim noktası olarak seçildiği için bu noktada yeni bir ilgi nesnesi yaratılır ama tavsiye çalışmaz.

  3. main metod içerisinde doWhat metodunun çağırılması da aynı şekilde bir birleşim noktası olarak seçildiği için bu noktada yeni bir TraceAspect nesnesi yaratılır ama nesnenin tavsiye yapısı çalışmaz.

  4. Son ilgi örneği isOkay metodunun çağırılmasıyla oluşturulur fakat tavisyesi cflowbelow özelliği devreye girdiği için bu nokta pas geçilir. Kısaca, main metodundaki Library sınıfına ait nesnelerden çağırılan metodlar bu yapı ile pas geçilir.

Pertypewithin Yapısı

Tipin (arayüz, sınıf, ilgi) nesnesi ile birleşmek yerine direkt tipin kendisi ile birleşen noktalarda ilgi örneklemesinin yapılmasını sağlar. Eğer belirlenen tipin içinde çalışması istenen ilgi örneği tarafından yakalanan birleşim noktaları varsa, bu noktalar devreye girer. Bu özellik ata-çocuk ilişkili tipler arasında özel ilgi örnekleri yaratılması için kullanılabilir.

Örnek 6) Bir 'pertypewithin' özelliğine sahip TraceAspect ilgisi:
...
... Library sınıfına ait değişmeyen metodlar
...

package com.kodcu.concerns.aspects;
import com.kodcu.concerns.core.Library;
public aspect TraceAspect pertypewithin(com.kodcu.tests.Test) {   (1)
    ...
    ... Değişmeyen kodlar
    ...
    after(Library lib) :doTrace(lib){
        System.out.println("Join Point: " + thisJoinPointStaticPart
         + "Aspect: " + this
         + "Object: " + lib
         + "Type Name associated with the Aspect instance '"
         + getWithinTypeName()+"'");                            (2)
    }
}


package com.kodcu.tests;
import com.kodcu.concerns.core.Library;
public class Test {

    public static void main(String[] args) {
        Library milliKutuphane = new Library();
>>      milliKutuphane.doSomething();
>>      milliKutuphane.doNothing();
        Library kutuphane = new Library();
>>      kutuphane.doWhat();
        Runnable ru = () -> System.out.println("**");
        ru.run();
        anotherMethod();
    }
    public static void anotherMethod() {
        Library yeniKutuphane = new Library();
>>      yeniKutuphane.isOkay();
        Store store = new Store();
        store.getStoreID();
    }
}
  1. Test sınıfı için ayrı ilginin yaratılması istenmektedir. Eğer pertypewithin yapısına sahip ilgi içinde Test sınıfı dahilinde birleşim noktaları varsa, ilgi nesnesine ait bileşenler bu noktalarda çalışmaktadır.

  2. pertypewithin yapısına özel ilgi birimlerinde ara tip tanımlamarında hariç diğer gövdeye sahip elementlerde getWithinTypeName metodu çağırılabilir. Bu metod ilgi örneği ile birleşen tipin tam ismini döndürmektedir.

Çıktı:
Creating TraceAspect instance                                           (1)
Join Point: call(void com.kodcu.concerns.core.Library.doSomething())
    Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
    Object: com.kodcu.concerns.core.Library@9ee92
Type Na me associated with the Aspect instance 'com.kodcu.tests.Test'
Join Point: call(void com.kodcu.concerns.core.Library.doNothing())
    Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
    Object: com.kodcu.concerns.core.Library@9ee92
    Type Name associated with the Aspect instance 'com.kodcu.tests.Test'
Join Point: call(void com.kodcu.concerns.core.Library.doWhat())
    Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
    Object: com.kodcu.concerns.core.Library@f39991
    Type Name associated with the Aspect instance 'com.kodcu.tests.Test'
**
Join Point: call(boolean com.kodcu.concerns.core.Library.isOkay())
    Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
    Object: com.kodcu.concerns.core.Library@1d6c5e0
    Type Name associated with the Aspect instance 'com.kodcu.tests.Test'
  1. Sadece Test içerisinde meydana gelecek birleşim noktalarında çalışacak tek tip ilgi örneği yaratılmaktadır.

Yardımcı İlgi Üyeleri

AspectJ dili ile birlikte ilgi nesnelerine özel yardımcı üyeler de gelmektedir. Sistemde farklı örnekleme davranışları sergileyen ilgiler için kullanışlı özelliğe sahip olan bu üyeler hem sınıf hem de ilgi bünyesinde çalışmaktadır.

Yardımcı statik üyeler:

  • aspectOf(): Bir ilgi birimi içerisinde this özelliği nasıl ilginin nesnesini bize döndürüyorsa, bu özel metod da aynı işleve sahiptir. İlgi içinde yaratılan geleneksel Java bileşenlerini bu method çağırımı ile de ulaşmamız mümkündür. this den farklı olarak, aspectOf metodunu sınıfların içerisinde de kullanabiliyoruz. İlgi içinde tanımlanan metod ve alan gibi üyelerin erişim belirleyicilerine göre başka sınıfların içerisinde çağırılabilirler. Farklı örnekleme yapısına sahip ilgiler doğrultusunda bu statik metod bir parametre alabilir. Ayrıca, hem aspectOf hem de thisAspectInstance if pointcut yapısının içerisinde çalışmakta olup, aralarındaki fark thisAspectInstance değişkeninin somut/soyut ilgi yapıları ile daha sık kullanılmasıdır. Eğer bir sınıfa bağlı bir ilginin nesnesi mevcut olmadığı halde bu statik metod çalıştırılırsa, NoAspectBoundException istisnası çalışma zamanı fırlatılır.

  • hasAspect(): Hem ilgi hem de sınıf içinde kullanılan bir statik yardımcı metoddur. İlgiye ait olan bu metodun parametre alıp alamayacağı ilginin yapısına göre değişiklik gösterir. hasAspect metodu çalıştırıldığında geriye boolean true/false değeri döndürür. Bu değerler ilgi nesnesinin bir tip nesnesine bağlanıp bağlanmadığını anlatır.

Bir singleton ilgiye sahip sistemin aspectOf ve hasAspect metodlarını kullanması:

package com.kodcu.concerns.aspects;
import com.kodcu.concerns.core.Library;
public aspect TraceAspect{
    /* Constructor */
    public TraceAspect() {
        System.out.println("Creating TraceAspect instance");
    }
    pointcut doTrace(Library lib) : call(* *(..))  && target(lib);

    after(Library lib) :doTrace(lib){
        System.out.println("Join Point: " + thisJoinPointStaticPart
         + "Aspect: " + TraceAspect.aspectOf()                                  (1)
         + "Object: " + lib
         + "is the aspect TraceAspect has an Aspect instance? :"+hasAspect() ); (2)

        TraceAspect.aspectOf().doItAspect();    (3)
        this.doItAspect();                      (4)
    }
    public void doItAspect(){
    	System.out.println("doing it...");
    }
}

package com.kodcu.tests;
import com.kodcu.concerns.aspects.TraceAspect;
import com.kodcu.concerns.core.Library;
public class Test {
    public static void main(String[] args) {
        Library library = new Library();
        library.doWhat();
        System.out.println("*************");
        TraceAspect.aspectOf().doItAspect();            (5)
        System.out.println(TraceAspect.hasAspect());    (6)
    }
}
Sistemin dökümü:
Creating TraceAspect instance
Join Point: call(void com.kodcu.concerns.core.Library.doWhat())
	Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
	Object: com.kodcu.concerns.core.Library@9ee92
	is the aspect TraceAspect has an Aspect instance? :true
doing it...
doing it...
*************
doing it...
true
  1. İlgi içinde this yerine yazılan TraceAspect.aspectOf() ya da sadece aspectOf() bize global ilginin nesnesini döndürür.

  2. İlgi içinde hasAspect() ya da TraceAspect.hasAspect() kısaca global TraceAspect ilgisinin sistemde genel bir nesnesi olduğunu gösterir.

  3. Tavsiye yapısı içerisinde doItAspect metodunu aspectOf ile çağırabiliyoruz. Aynı işlemi (4) gösterdiği gibi this ile de yapabiliriz

  4. İlginin nesnesinden yararlanarak doItAspect metodunu tavsiye içinde çağırıyoruz. İlgi içerisinde (3) ile aynı davranışa sahiptir.

  5. Belirtildiği gibi statik aspectOf sınıfların içerisinde de kullanılmaktadır. main metodun içerisinde ilginin nesnesine ait olan doItAspect metodu çağırılıyor. TraceAspcet ilgisi global olduğu için statik metod parametre almaz.

  6. Aynı şekilde statik method olan hasAspect, başka sınıflar içerisinde de kullanılır. Bu örneğimizde Test sınıfı içinde kullanılmaktadır.

Farklı bir örnek ile bu sefer bir pertypewithin ilgiye sahip sistemin aspectOf ve hasAspect kullanımını görelim:

package com.kodcu.concerns.aspects;
import com.kodcu.concerns.core.Library;
import com.kodcu.tests.Test;

public aspect TraceAspect pertypewithin(Test){
    /* Constructor */
    public TraceAspect() {
        System.out.println("Creating TraceAspect instance");
    }
    pointcut doTrace(Library lib) : call(* *(..))  &&
    								target(lib);

    after(Library lib) :doTrace(lib){
        System.out.println("Join Point: " + thisJoinPointStaticPart
         + "Aspect: " + aspectOf(Test.class)
         + "Object: " + lib
         + "Type Name associated with the Aspect instance '"
         + getWithinTypeName()+"'"
         + "is the class Test has an Aspect instance? :"+hasAspect(Test.class) ); (1)
    }
    public void doItAspect(){
    	System.out.println("doing it...");
    }
}




package com.kodcu.tests;
import com.kodcu.concerns.aspects.TraceAspect;
import com.kodcu.concerns.core.Library;

public class Test {

    public static void main(String[] args) {
        Library library = new Library();
        library.doNothing();

        System.out.println("*************");
        TraceAspect.aspectOf(Test.class).doItAspect();          (2)
        System.out.println(TraceAspect.hasAspect(Test.class));  (3)

        TraceAspect.aspectOf(Library.class).doItAspect();       (4)
    }
}
Çıktı:
Creating TraceAspect instance
Join Point: call(void com.kodcu.concerns.core.Library.doNothing())
    Aspect: com.kodcu.concerns.aspects.TraceAspect@84aee7
    Object: com.kodcu.concerns.core.Library@9ee92
    Type Name associated with the Aspect instance 'com.kodcu.tests.Test'
    is the class Test has an Aspect instance? :true
*************
true
Exception in thread "main" org.aspectj.lang.NoAspectBoundException
    at com.kodcu.concerns.aspects.TraceAspect.aspectOf(TraceAspect.aj:1)
    at com.kodcu.tests.Test.main(Test.java:18)
  1. pertypewithin yapısı alan ilgi içerisinde aspectOf metodu bir Java Class nesnesi istemektedir. İlgimiz, Test ve ondan türeyen sınıflarda çalıştığı için parametre olarak Test sınıfının yazıyoruz. Çıktı olarak TraceAspect ilgisinin Test sınıfına ait bir nesnesi olduğunu bize doğrular (true).

  2. Mevcut ilgi TraceAspect artık global olmadığından dolayı statik metodları parametre almaktadır çünkü TraceAspect ilgisi artık direkt tipe bağlı olarak sistemde yaşamaktadır. Bu yüzden sınıflar içerisinde de bu metodları çağırırken parametre olarak bir Java Class nesnesi vermemiz gerekmektedir. Kısaca satır, Test sınıfı bünyesinde TraceAspect ilgisine bağlı olan nesneden doItAspect metodunu çağır demektedir.

  3. Bu işlemi hasAspect metodu içinde yapmaktayız. Test sınıfı bünyesinde TraceAspect ilgisine bağlı bir nesnenin olup olmadığını anlıyoruz.

  4. Son satırda çalışma zamanı karşılaşılan NoAspectBoundException istisnası bize kısaca Library sınıfı bünyesinde TraceAspect ilgisine bağlı bir nesneden doItAspect metodunu çalıştırmaya teşebbüs edildiği ancak mevcut ilginin bir nesnesi o sınıf için bulunmadığından hata vermek zorunda kaldığını söylemektedir.

Note
Control-based örnekleme yapılarına — percflow ve percflowbelow — sahip ilgiler bu metodları parametre vermeden kullanır. Object-based örnekleme yapılarına — perthis ve pertarget — sahip ilgiler bu metodları tip nesnesini/örneğini parametreye vererek kullanır.

Aspect Precedence

Farklı sistem davranışlarına göre birden fazla ilgi birimi içinde tanımlanan tavsiyeler aynı birleşim noktalarında çakışabilir. Bu gibi durumlarda istenmeyen sırada çalışan crosscutting ilgilerin öncelik sıralarının ayarlanması gerekebilir. declare precedence yapısı ile ilgileri kendi aralarında sıralayarak bu ilgilerden doğan tavsiyeler de sıralanmış olurlar.

Declare Precedence Yapısı:
    declare precedence: [TipİmzaDeseni1], [TipİmzaDeseni2], ...; (1)

    declare precedence: LoggingAspect, PoolingAspect; (2)

    declare precedence: Log*, Pool*; (3)
  1. En az iki ilgi biriminin işaret edilmesiyle ilgilerin öncelik sıraları tekrar şekillenir.

  2. İki ilginin sıralanması gösterilmektedir. İlgilerin sıralanma düzeni tavsiye yapılarına göre değişmektedir. Örneğin PoolingAspect ve LoggingAspect içerisindeki after advice yapısı olursa, PoolingAspect ilgisinin önceliği LoggingAspect ilgisine göre daha yüksektir. Eğer before advice yapısı varsa PoolingAspect ilgisinin önceliği LoggingAspect ilgisine göre daha düşüktür (after ile tam tersi). Son olarak around advice yapılarında, işaret edilen ilgi birimleri iç içe geçerek bir sıralama düzeni oluşturur ve en dıştan içe doğru gidildiğinde ilgilerin öncelik sırası azalır. Örneğin; LoggingAspect ilgisinin önceliği daha yüksektir çünlü en dışta bulunur ve onun içine PoolingAspect ilgisi yerleşir.

  3. İlgileri belirtirken özel sembollerden yıldız (*) da kullanılabilir. Eğer after advice yapısına göre sıralama yapılırsa, tüm Log ile başlayan ilgi birimlerinin tavsiye önceliği azaltılıp, tüm Pool ile başlayan ilgilere yüksek öncelik verilmektedir.

declare precedence örneği:
package com.kodcu.order;
public aspect LogingAspect {
    after(): call(* com.kodcu.concerns.core.Library.doNothing()){
        System.out.println("Logging concerns...");
    }
}
package com.kodcu.order;
public aspect AuthenticationAspect {
    after(): call(* com.kodcu.concerns.core.Library.doNothing()){
        System.out.println("Authentication concerns...");
    }
}
package com.kodcu.order;
import com.kodcu.order.AALogingAspect;
import com.kodcu.order.AuthenticationAspect;
public aspect OrderAspect {
    declare precedence: AuthenticationAspect, LogingAspect; (1)
}
package com.kodcu.tests;
import com.kodcu.concerns.core.Library;
public class Test {
    public static void main(String[] args) {
        Library library = new Library();
        library.doNothing();
    }
}
İstenen Düzen:
Logging concerns...
Authentication concerns...
  1. Library sınıfına ait doNothing metodunun çağırıldığı noktada hem LogingAspect hem de AuthenticationAspect ilgilerindeki after tavsiye yapıları çakışmaktadır. Sistemde ilk loglamanın yapılması istendiği için OrderAspect ilgisinde declare precedence yapısı kullanılarak bu ilgilerin öncelikleri istenildiği şekilde tekrar düzenlenmektedir. Böylelikle ilk logging ilgileri sonra authentication ilgileri çalışmaktadır. Eğer precedence yapısı kullanılmazsa sistemde ilk hangi tavsiye yaratılmışsa o ilginin önceliği yüksek olur.

'around advice' yapılarında 'declare precedence' kullanımı:
package com.kodcu.order;
public aspect LogingAspect {
    void around(): call(* com.kodcu.concerns.core.Library.doNothing()){
        System.out.println("Logging concerns...");
        proceed();
    }
}
package com.kodcu.order;
public aspect AuthenticationAspect {
    void around(): call(* com.kodcu.concerns.core.Library.doNothing()){
        System.out.println("Authentication concerns...");
    }
}
package com.kodcu.order;
import com.kodcu.order.AALogingAspect;
import com.kodcu.order.AuthenticationAspect;
public aspect OrderAspect {
    declare precedence: LogingAspect, AuthenticationAspect; (1)
}
package com.kodcu.tests;
import com.kodcu.concerns.core.Library;
public class Test {
    public static void main(String[] args) {
        Library library = new Library();
        library.doNothing();
    }
}
İstenen Düzen:
Logging concerns...
Authentication concerns...
  1. Around tavsiyelerinin çakıştığı bir birleşim noktasında önceliğin en yüksek olması istenen ilgi en başa yazılır ve sonrakiler bir öncekinin içine geçecek şekilde arka planda sıralanır. İç içe geçmiş ilgi sıraları around tavsiyeleri için: [ LoggingAspect { AuthenticationAspect { …​ } } ]. İlgiler iç içe geçtiği için en dışta olan ilginin tavsiyesi çalışacaktır. İçte kalan ilgilere ait around tavsiyelerin de çalışması istenirse, around yapıları içinde proceed metodunu çağırarak ayarlanan sırada gereken tavsiyeleri çalıştırmış oluruz.

Privileged Aspect

AspectJ ile birlikte sistemde istenilen ilgi birimlerine ayrıcalık özelliği de getirilebilir. Sınıflar gibi ilgiler de başka birimlerin içerisinde oluşturulan private yapılı metod ve alanlara erişememektedir. AspectJ dilinde istenilen ilgilere ayrıcalık yapılması halinde bu ilgiler tavsiye gövdelerinde sınıfların private özelliğe sahip üyelerine erişme hakkı verilir. İlgileri bu erişime açmak için privileged anahtar kelimesi kullanılır. Bu kelime ilgi tanımlama kısmında en başa yazılır.

public class Main {
    private int id = -1;
    public static void main(String... args) {
        Main main = new Main();
        main.doSomething();
    }
    public void doSomething() {
        System.out.println("doing something...");
    }
}
privileged public aspect PrivilegedAspect {
    before(Main main) : call(* Main.doSomething()) &&
                        target(main) {
        System.out.println("PrivilegedAspect :: Id: " + main.id);(1)
    }
}
Çıktı
PrivilegedAspect :: Id: -1
doing something...
  1. Privileged karaktere sahip ilginin tavsiye yapısı, Main sınıfın private yapılı id alanına kolaylıkla erişebiliyor.