Skip to content

Latest commit

 

History

History
536 lines (435 loc) · 25 KB

chapter-05.asc

File metadata and controls

536 lines (435 loc) · 25 KB

Advice Yapısı

Pointcut yapılarıyla tam olarak tavsiyelere ne zaman başvurağımızı belirtirken, tavsiye (advice) yapılarıyla da tam olarak ne yapacağımızı belirtiyoruz. AspectJ dili dinamik crosscutting özelliğini tavsiye yapıları aracılığıyla sağlamaktadır. Sistemin gereksinimine göre belli senaryolarla birlikte enine kesen ilgileri farklı zamanlarda çalıştırmak isteyebiliriz. Sistemin davranışını belli noktalarda (yani belli birleşim noktalarında) tavsiye yapılarıyla bağlanan pointcut’lar ile beraber değiştirme imkanına sahip oluyoruz. AspectJ 3 çeşit tavsiye sunmaktadır:

  • Before Advice

    • Birleşim noktasının çalışmasından önce çalışan tavsiye yapısı.

  • After Advice

    • After advice, birleşim noktasının çalışmasından sonra işleme girer. Ayrıca bu yapı kendi içinde 3 sınıfa daha ayrılmaktadır:

      • After (finally) Advice: Bağlanan yerin sonucuna bakılmaksızın, birleşim noktalarından sonra çalışan yapıdır. Bu özelliği ile aynı zamanda after finally advice olarak da gösterilir.

      • After Throwing Advice: Birleşim noktalarında beliren hata fırlatmalarından sonra çalışması istenen advice yapısıdır.

      • After Returning Advice: Başarıyla çalışan ve biten birleşim noktalarından sonra çalışması istenen yapıdır. İstisna fırlatmanın yaşanmadığı noktalarda devreye girmektedir.

  • Around Advice

    • Özel bir yapı olan around advice, eşlenen birleşim noktalarını çevreleyen bir özelliğe sahiptir. Bu yapı, eşlenen birleşim noktalarının içeriğinde değişiklik yapmadan ya da yaparak çalıştırabilir, ayrıca sistemdeki bu noktaları devre dışı bırakabilir ya da birden fazla çalışmasına izin verebilir.

Tavsiye Oluşumu

Tavsiye, metod tanımlamasına benzer bir özelliğe sahiptir. Daha önce de bahsedildiği gibi (Bkz. [AspectJ Dili]) aspect birimi içerisindeki yeni bileşenler derlenerek Java bileşenlerinin yapısını almaktadırlar. Tavsiyeler de byte kod dönüşümü sonrasında metod davranışa sahip olurlar. Tavsiye tanımlaması yapılarına göre biraz değişiklik gösterebilir ama genel tanımlama olarak aşağıdaki düzen içerisinde bir tavsiye yaratılmaktadır:

Tavsiye Anatomisi
    @AdviceName("advicename") (1)
    <advice tanımlaması> :    (2)
    <pointcut tanımlamaları>  (3)
    {
        // tavsiye gövdesi    (4)
    }
  1. AspectJ, org.aspectj.lang.annotation paketinin içerisindeki AdviceName notasyonu ile istenilen tavsiye yapısına isim verilmesini sağlar. Opsiyonel bir özelliktir.

  2. Hangi tavsiye yapısı olacağını belirten ilk bölge.

  3. pointcut yapılarıyla oluşan bölge. Birleşim noktaları ile tavsiyenin eşlendiği yerdir.

  4. Metod gövdesi ile aynı özelliğe sahiptir. AspectJ ile birlikte gelen bazı özel değişkenler de bu gövde içinde kullanılır.

Important
Tavsiye yapıları, çalışma zamanında AspectJ Weaver ile metod yapısına dönüştüğü için tavsiye yapılarına isim verme işlemi gene çalışma zamanında belirlenmektedir. Çalışma zamanı belirlenen örnek bir tavsiye ismi: ajc$after$com_book_aspects_AspectModule$2$e0a2f451. $2$e0a2f451 ifadesindeki ilk bölge ($2$), ilgi biriminin içinde üstten 2. sırada olan tavsiye birimi olduğunu göstermekte ve her tavsiye için bir hash değeri verilmektedir. @AdviceName notasyonunu sadece tavsiyeleri birbirlerinden ayırt etmek için kullanırız. Aynı isme sahip birden fazla tavsiye tanımlaması hataya neden olmaz.
Örnek 1) bir after() returning() tavsiyesi:
aspect AspectModule {
    after() returning(String ret):              (1)
            call(* com.book.Library.doSomething(String,..)) {
        // advice body
    }
}
  1. returning() içerisinde tanımlanan değer (yani ret), doSomething metodundan geriye dönen değeri temsil etmektedir. Ayrıca, bu değeri tavsiye gövdesinin içerisinde farklı amaçlar doğrultusunda kullanabiliriz.

Advice vs Method

Tavsiye yapılarının metod yapılarına benzer olduğu belirtilmişti. Tavsiye yapıları, AOP yaklaşımının gerçekleşeceği bölgeler olarak benimsenmektedir. Enine kesen ilgilerin belirlenen noktalara tavsiyelerde bulunmasını en kolay şekilde geliştiricilere sunmak adına bu yapı Java’nın metod yapısına benzer şekilde tasarlanmıştır. Bu 2 yapı arasında elbette benzerlikler ve farklılıklar olmaktadır. Benzerlikler ile tavsiye yapılarına alışılması daha kolay olacağı gibi farklılıklar ile AspectJ dilinin bize kazandırdığı değişik fonksiyonları da görmüş olacağız.

İki yapı arasındaki benzerlikler
  1. Tavsiye yapıları da metodlar gibi parametre alabilmektedir. Bu parametreler birleşim noktalarından gelen bilgileri bize döndürmektedir. Ayrıca, bunlar tavsiye gövdesinde farklı amaçlar için kullanılabilir.

  2. Tavsiyeler de istisna (hata) fırlatabilir.

  3. Tavsiye gövdeleri metod gövdelerindeki özelliklerin tümünü karşılamaktadır.

  4. this anahtar kelimesi, mevcut nesnenin (yani aspect nesnesi) referansı olarak metod gövdesinde kullanıldığı gibi kullanılabilir.

  5. Sadece around advice yapısında dönüş tipi belirlenebilir ve geriye değer döndürür.

  6. Runtime istisnalar fırlatabilir.

  7. Eğer birleşim noktaları metod ise ve bu metodlar birden fazla istisna fırlatma yeteneğine sahipse, tavsiye yapıları içlerinden sadece 1 tanesini fırlatabilir.

Tavsiyenin metod olmadığını belli eden farklılıklar
  1. Opsiyonel olarak tavsiyeleri birbirinden ayırmak için isimlendirilebilir.

  2. Direkt olarak çağrılamazlar. Runtime içerisinde bu tavsiyelerin çağırılmasını sağlayan işlemler mevcuttur.

  3. Erişim belirleyicilerine sahip değiller.

  4. After advice ve before advice yapıları değer döndürmezler.

  5. Around advice yapısına özel proceed() metodu vardır.

  6. Tavsiye gövdesinin içinde kullanılacak özel değişkenler mevcuttur.

Important
Tavsiye yapıları sistemin çalışma akışını değiştirme özelliğine sahiptirler.

Before Advice

Before advice yapısı, birleşim noktasında bulunan esas kodlardan önce çalışmaktadır. Bu yapının içinde fırlatılan hata sistemin sonlanmasına neden olur. Enine kesen ilgilerden tracing, security ve validation işlemlerinde bu yapı daha sık kullanılmaktadır.

Örnek 2) bir before() tavsiye yapısı:
package com.book.info;
public class Library {

    public void doSomething(int param1){
    	// core concerns
    	System.out.println("core concerns in progress...");
    }
}
package com.book.aspects;
public aspect ValidationAspect {                           (1)

    void outError(String msg) {
    	System.err.println("Error: " + msg);
    	System.exit(0);
    }

    before(int param1) : execution(* do*(int)) && args(param1) {
        // advice body
        if (param1 <= 0)
            this.outError("number must be greater than 0");
    }
}
package test;
import com.book.info.Library;
public class Test {
    public static void main(String... args) {
    	Library lib = new Library();
>>      lib.doSomething(0);
    }
}
Çıktı
Error: number must be greater than 0
  1. Validation işleminin sitemde farklı sınıflara saçıldığını düşünelim ve sistemde tüm do* ile başlayan metodların çağırılmasından önce girilen parametrenin doğru olup olmadığına bakalım.

Eğer yukarıda yapılan yaklaşımı AspectJ kullanmadan yapsaydık sistemin mevcut görünümü şu şekilde olabilirdi:

Örnek 3)
package com.book.info;
public class Library {

    public void doSomething(int param1){
    	// core concerns
    	System.out.println("core concerns in progress...");
    }
}

package com.book.utility;
public class Print {                                    (1)
    public static void outError(String msg) {
    	System.err.println("Error: " + msg);
    	System.exit(0);
    }
}

package test;
import com.book.info.Library;
public class Test {

    public static void main(String... args) {
    	Library lib = new Library();
        // crosscutting concern                         (2)
        int param1 = 0;
        if (param1 <= 0)
            Print.outError("number must be greater than 0");
>>      lib.doSomething(param1);
    }
}
Çıktı
Error: number must be greater than 0
  1. Yeni yaratılan bir public Print sınıfı oluşabilir

  2. Sadece bir tanesi gösterilen ama do* ile başlayan tüm metodların sistemde çok fazla bulunduğunu ve hepsinin aynı doğrulamayı yaptığını düşünürsek, bu enine kesen ilginin çok fazla alana saçılacağını da söyleyebiliriz.

After (Finally) Advice

After advice yapısı, birleşim noktalarının çalışmasından sonra gerçekleşecek enine kesen ilgi eylemlerinin çalışmasını sağlamaktadır. Genel olarak birleşim noktalarındaki dönüş değerleri tek tip gelmemektedir. AspectJ dili bu yüzden after advice adı altında 3 farklı yapı sunmaktadır. After finally yapısı, hata dönsün ya da dönmesin her koşulda birleşim noktalarından sonra çalışır.

Örnek 4) bir after() finally advice örneği:
package com.book.aspects;
public aspect LoggingAspect {
    after() : call(* com.book.info.Library.*(..)) {    (1)
        // log after methods calls declared in Library
    }
}

package test;
import com.book.info.Library;
import com.book.store.StoreBook;
public class Test {

    public static void main(String... args) {
        Library lib = new Library();
>>      lib.anyMethodDeclaration();
>>      lib.staticMethod();
>>      Library.staticMethod2();

        StoreBook store = new StoreBook();
        store.doNothing();
    }
}
  1. Library nesnesine ait ve Library sınıfına ait (statik) tüm metod çağırmalarından sonra çalışan tavsiye tanımlaması.

AOP yaklaşımını kullanmadan önceki geleneksel loglama sisteminde, log yapılacak noktaları kendimiz bizzat tespit ederek çağırılan metodlardan sonra her durumda çalışacak kodları sistemin içine entegre etmemiz gerekecekti:

Örnek 5)
package test;
import com.book.info.Library;
import com.book.store.StoreBook;
public class Test {

    public static void main(String... args) {
        Library lib = new Library();
        try {
    	    lib.anyMethodDeclaration();
        } finally {                         (1)
            // log after calling anyMethodDeclaration()
        }
        try {
            lib.staticMethod();
        } finally {                         (2)
            // log after staticMethod()
        }
        try {
            Library.staticMethod2();
        } finally {                         (3)
            // log after staticMethod2()
        }

        StoreBook store = new StoreBook();
        store.doNothing();
    }
}
  1. Her koşulda Library sınıfına ait metodların çağırılmasından sonra log işleminin çalışması için, çağırılan metodları try {} bloğu içine alıp finally {} bloğu ile bitirmek gerekmektedir.

  2. Aynı işlemler bu satırda da yapılıyor.

  3. Aynı işlemler bu satırda da yapılıyor.

After Returning Advice

Sorunsuz olarak biten birleşim noktalarından sonra çalışan tavsiye yapılarıdır. Bu yapı sayesinde birleşim noktasının void dışında geri dönüş tipini de tavsiye bloğunun içerisinde kullanabiliyoruz.

Örnek 6) bir after() returning() advice örneği:
package com.book.aspects;
public aspect LoggingAspect {
4>  after() returning() : call(* com.book.info.Library.*(..)) {     (1)
        // log after methods calls declared in Library
    }

1>  after() returning(String ret) :                                 (2)
            call(String com.book.info.Library.doArchive(..)) {
        // log after doArchive()
    }
}

package test;
import com.book.info.Library;
import com.book.store.StoreBook;
public class Test {

    public static void main(String... args) {
        Library lib = new Library();
>>      lib.anyMethodDeclaration();
>>      lib.staticMethod();
>>      Library.staticMethod2();
>>>>    String result = lib.doArchive();                            (3)
    }
}
  1. Bu tavsiye yapısı 4. örnekteki ile aynı fonksiyonelliğe sahiptir yalnız çağırılan metodların her hangi birinde oluşacak hata fırlatımı after() finally gibi çalışmasına engel olacak ve gereken ilgi kodları çalışmayacaktır. Dönüş tipi belirtilmediği (returning()) için bu tavsiye main() metodu içindeki 4 birleşim noktasınada bağlanır. (>>, birleşim nokta gölgelerini göstermektedir).

  2. Dönüş tipi String olan doArchive metoduna bağlanır.

  3. Toplam 2 tavsiye yapısı bu birleşim noktasına bağlanmıştır ( (1) ve (2) ). Birden fazla tavsiye bağına sahip birleşim noktalarının çalışma akışı tavsiyelerin oluşturulma düzenine göre belirlenir. Bu örneğimizde LoggingAspect biriminin içinde ilk (1) sonra (2) tanımlandığı için sistem (3) → (1) → (2) sırasında çalışacaktır.

Important
Eğer bir birleşim noktasına bir ilgi biriminde oluşturulmuş birden fazla tavsiye yapısı bağlanıyorsa, o noktada tavsiyelerin çalışma sırası yaratıldıkları sıraya göre belirlenir (en yukarıdan aşağıya doğru) (Bkz. örnek 6). Eğer bir birleşim noktasına farklı ilgi birimlerinde oluşturulan tavsiye yapıları bağlanıyorsa, çalışma akışını belirlemek için aspect precedence özelliği kullanılmaktadır. Bu özellik aspect bölümünde detaylı anlatılacak.

After Throwing Advice

After returning tavsiyesine benzer özelliktedir. Birleşim noktasının çalışmasında meydana gelen istisna fırlatımı sonrası çalışan tavsiye yapısıdır. Normal şartlarda sorunsuz çalışan bir metod çağırma ya da yürütme noktasından sonra bu yapı çalışmaz.

Örnek 7) bir after() throwing() advice örneği:
package com.book.aspects;
public aspect AspectModule {

    after() returning(): call(* com.book.info.Library.*(..)){                   (1)
    	System.out.println("After returning!");
    }

    after() throwing() : call(* com.book.info.Library.*()){                     (2)
    	System.err.println("After throwing!");
    }

    after() throwing(Exception ex) : call(* com.book.info.Library.*()){
    	System.err.println("After throwing! exception : "+ ex.getMessage());    (3)
    }
}

package com.book.info;
public class Library {

    public void doException() throws Exception {
        throw new Exception("an exception occurs!");
    }
}

package test;
import com.book.info.Library;
public class Test {
    public static void main(String... args) {
    	Library lib = new Library();
    	try {
>>          lib.doException();                                                  (4)
    	} catch (Exception e) {
            System.err.println("catch block");
    	}
    }
}
Çıktı:
1 After throwing!
2 After throwing! exception : an exception occurs!
3 catch block
  1. doException metoduna bağlı olan tavsiye, metodun hata fırlatmadığı zamanlar çalışacak

  2. doException metodunun istisna çıkarttığı durumdan sonra çalışacak olan tavsiye yapısı. Fırlatılan istisnanın bilgilerine bu tavsiye yapısında ulaşamıyoruz.

  3. doException metodunun istisna çıkarttığı durumdan sonra çalışacak olan tavsiye yapısı. Fırlatılan istisnanın bilgilerine bu tavsiye yapısında ulaşabiliyoruz. throwing(Exception ex) parametresinde tanımlı istina türü ile tavsiyenin gövdesinde farklı senaryolar için kullanılabilir.

  4. Hedef alınan birleşim noktası.

Around Advice

Around advice, birleşim noktalarını çevreleyen bir yapıya sahiptir. Bu yapı, pooling, caching, tracing, exception handling ve transaction management ilgileri için kulanılabilir. Diğer tavsiye yapılarından farklı olarak around yapısı:

  1. before advice ve after (finally) advice özelliğini barındırır.

  2. Birleşim noktasını aynı ya da farklı içerikler ile çalıştırabilir.

  3. Birleşim noktalarının birden fazla çalışmasını sağlayabilir.

  4. Birleşim noktalarının çalışmasını atlayabilir.

  5. Özel proceed() metodu sayesinde birleşim noktasını tavsiye içerisinde çalıştırabilir.

  6. Dönüş tipine sahiptir.

Örnek 8)
package com.book.info;
public class Library {

>>  public String doSomethingLibrary() {
        System.out.println("doSomethingLibrary: core concerns in progress...");
        return "result +";
    }

>>  public void doSomething(int param1){
        // core concerns
        System.out.println("doSomething: core concerns in progress...");
    }

>>  public void doException() throws Exception {
        throw new Exception("an exception occurs!");
    }

}
package com.book.aspects;
public aspect AspectModule {
    void around() : execution(* doException() throws Exception){            (1)
    	try {
            proceed();                                                      (2)
    	} catch (Exception e) {
            System.out.println("around body :: Caught Exception : "+ e.getMessage());
    	}
    }

    void around() : execution(* com.book.info.Library.doSomething(..)){     (3)
        System.out.println("around body :: NEW core concerns in progress...");
    }

    String around() : execution(* com.book.info.Library.doSomethingLibrary(..)){ (4)
        String jpoint = proceed();                                               (5)
        jpoint += " after advice behavior :: additional actions "+
                  "after the execution of doSomethingLibrary()!";
        return jpoint;
    }
}

package test;
import com.book.info.Library;
public class Test {
    public static void main(String... args) {
        Library lib = new Library();
        String result = lib.doSomethingLibrary();
        System.out.println(result);
        lib.doSomething(0);

        try {
            lib.doException();
        } catch (Exception e) {
            e.printStackTrace();                (6)
        }
    }
}
Çıktı:
1 doSomethingLibrary: core concerns in progress...
2 result + after advice behavior :: additional actions after the execution of doSomethingLibrary()!
3 around body :: NEW core concerns in progress...
4 around body :: Caught Exception : an exception occurs!
  1. Exception hatası fırlatan her bir doException metodunu çevreliyor. doException metodunu olduğu gibi kapsamaktadır. Sistemde bu metod yerine bağlanan tavsiye yapısının önceliği vardır.

  2. proceed() metodu ile Library sınıfı içerisinde oluşturulan doException metodunu çağırıyor.

  3. Library sınıfı içindeki doSomething metodunu çevreliyor. Around tavsiyesi proceed() metodunu kullanmadığı için doSomething metodu sistemin çalışma akışında kullanılmıyor. Bu metod yerine around tavsiyesi sistemde devreye giriyor.

  4. Library sınıfı içindeki doSomethingLibrary metodunu çevreliyor.

  5. proceed() metodu yardımıyla doSomethingLibrary metodunu çağırarak metodun içindeki esas kodların çalışmasını sağlıyor ve daha sonra ek ilgileri çalıştırıp geriye değer döndürüyor.

  6. Sistemin çıktısından da anlaşılacağı gibi e.printStackTrace(); yani catch bloğuna giriş yapılmamaktadır. Bu işlem (1)'de yaratılan around tavsiyesi içinde gerçekleşmektedir.

Important
Around advice yapısı sistemin çalışma akışını doğrudan etkileyebilir.

Özel Değişkenler

AspectJ, birleşim noktalarındaki statik ve dinamik içeriklere kolaylıkla ulaşılması için kendi bünyesinde oluşturduğu Reflection API içinde 3 özel değişken barındırmaktadır: thisJoinPoint, thisJoinPointStaticPart ve thisEnclosingJoinPointStaticPart. Her birleşim noktası, dinamik içerik bilgilerini tutan bir nesneden ve statik bilgileri barındıran iki nesneden oluşmaktadır. Örneğin; bir metod yürütme noktasındaki metodun ismi ve metodun bulunduğu dosyanın ismi ve satır numarası statik bir bilgi olduğu gibi aynı metod noktasının farklı nesneler ile çalıştırılmasından doğan bilgiler de dinamik olarak gözükmektedir.

  • thisJoinPoint : Tavsiye alan birleşim noktalarının dinamik bilgilerini döndürmektedir. Hedef nesneye, bulunduğu konumun nesnesine veya parametrelere bu değişken sayesinde ulaşabiliriz. thisJoinPoint.getStaticPart() komutuyla, birleşim noktasının statik bilgilere thisJoinPointStaticPart değişkeni kullanmadan da ulaşılabilir.

  • thisJoinPointStaticPart : Tavsiye alan birleşim noktalarının statik bilgilerini döndürmektedir. Birleşim noktasına ait değişmeyen özelliklere ( isim, dosya konumu, birleşim noktası türü, imza deseni ve bulunduğu dosyanın ismi gibi ) ulaşabiliriz.

  • thisEnclosingJoinPointStaticPart : Tavsiye alan birleşim noktalarını çevreleyen birleşim noktasına ait statik bilgilerini döndürmektedir. Eğer tavsiye alan bir birleşim noktasının bir üstünü (parent) yani onu çevreleyen birleşim noktasını öğrenmek için kullanılır.

package com.book.info;

import com.book.staff.Librarian;
import com.book.store.StoreBook;

public class Library {

>>  public void doSomethingLibrary() {
>>      StoreBook store = new StoreBook();
>>      store.doSomethingMore(null, 1);
>>      Librarian librarian = new Librarian();
>>      librarian.doSomethingLibrarian(null, 4);
    }
}

package com.book.staff;
import com.book.info.Library;
>> public class Librarian extends Library{

>>  public void doSomethingLibrarian(Object object, int b) {
>>      doNothing();
    }

>>  public void doAnything(Object object) {
>>      System.out.println("Voila!!");
    }

>>  public void doNothing() {
>>      doAnything(null);
    }
}

package com.book.store;
>> public class StoreBook {
    >> public void doSomethingMore(Object param1, int param2) {
       }
   }
package com.book.aspects;
import com.book.info.Library;
aspect AspectCflow {
    pointcut doPointcut():
                cflow(execution(* Library.doSomethingLibrary()))
                && !within(AspectCflow);

    before(): doPointcut(){
        System.out.println(thisJoinPoint.getKind() + " :: " +               (1)
                   thisJoinPointStaticPart.getSourceLocation() + " :: " +   (2)
                   thisEnclosingJoinPointStaticPart.toShortString());       (3)
    }
}
package test;
import com.book.info.Library;
public class Test {
        public static void main(String... args) {
            Library lib = new Library();
            lib.doSomethingLibrary();
            System.out.println("Done!");
        }
}
  1. Her bir birleşim noktasının türünü öğreniyoruz.

  2. Her bir birleşim noktasının bulunduğu dosya konumunu öğreniyoruz.

  3. Tavsiye alan birleşim noktalarını çevreleyen birleşim noktalarını öğreniyoruz.

Çıktı
method-execution :: Library.java:8 :: execution(Library.doSomethingLibrary())
constructor-call :: Library.java:9 :: execution(Library.doSomethingLibrary()) (1)
staticinitialization :: StoreBook.java:0 :: staticinitialization(StoreBook.<clinit>)
preinitialization :: StoreBook.java:2 :: preinitialization(StoreBook())
initialization :: StoreBook.java:2 :: initialization(StoreBook())
constructor-execution :: StoreBook.java:2 :: execution(StoreBook())
method-call :: Library.java:10 :: execution(Library.doSomethingLibrary())
method-execution :: StoreBook.java:4 :: execution(StoreBook.doSomethingMore(..))
constructor-call :: Library.java:11 :: execution(Library.doSomethingLibrary())
staticinitialization :: Librarian.java:0 :: staticinitialization(Librarian.<clinit>)
preinitialization :: Librarian.java:5 :: preinitialization(Librarian())
preinitialization :: Library.java:6 :: preinitialization(Library())
initialization :: Library.java:6 :: initialization(Library())
constructor-execution :: Library.java:6 :: execution(Library())
initialization :: Librarian.java:5 :: initialization(Librarian())
constructor-execution :: Librarian.java:5 :: execution(Librarian())
method-call :: Library.java:12 :: execution(Library.doSomethingLibrary())
method-execution :: Librarian.java:7 :: execution(Librarian.doSomethingLibrarian(..))
method-call :: Librarian.java:8 :: execution(Librarian.doSomethingLibrarian(..))
method-execution :: Librarian.java:15 :: execution(Librarian.doNothing())
method-call :: Librarian.java:16 :: execution(Librarian.doNothing())
method-execution :: Librarian.java:11 :: execution(Librarian.doAnything(..))
field-get :: Librarian.java:12 :: execution(Librarian.doAnything(..))
method-call :: Librarian.java:12 :: execution(Librarian.doAnything(..))
Voila!!
Done!
  1. StoreBook store = new StoreBook(); satırını incelersek: constructor-call türünde bir birleşim noktası olduğunu, Library.java dosyasının içinde 9. satırda bulunduğunu ve bu birleşim noktasını çevreleyenin de metod yürütme (method-execution) noktasına sahip doSomethingLibrary() metodu olduğunu görüyoruz.