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.
[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:
-
Erişim belirleyicisine sahip olabilir.
-
abstract
yapısında tanımlanabilir. -
extends
veimplements
yollarıyla diğer modüllere erişebilir. -
Farklı ilgi ilişkilendirmeleriyle yeni özelliklere sahip olabilir (ör.
pertarget(<Pointcut>)
). -
Kendi bünyesinde statik crosscutting, dinamik crosscutting yapılarını, pointcut, intertype tanımlamaları, metod, alan ve nested tip tanımlamaları yapılabilir.
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
-
-
public
,abstract
ve yafinal
belirleyiciye sahip olabililr. Nested ilgiler isepublic
,private
,protected
ya da paket (default) erişime sahip olurlar. -
Birimler içerisinde geleneksel Java elementlerinden alan ve metod tanımlamaları yapılabilir.
-
abstract
birim olarak nitelendirilebilirler. Soyut ilgi birimleri yaratılarak içlerinde pointcut ve metodların daabstract
olarak tanımlanabilinmesine izin verilmektedir. -
implements
veextends
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. -
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ınprivate
olan nesne değişkenlerine ve metodlarına ulaşabilir.
-
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ı:
-
issingleton()
-
perthis(Pointcut)
-
pertarget(Pointcut)
-
percflow(Pointcut)
-
percflowbelow(Pointcut)
-
pertypewithin(Tip İmza Deseni)
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.
public aspect Logging issingleton(){ (1)
// aspect body
}
public aspect Logging { (2)
// aspect body
}
-
(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.
-
(1) ile aynı özelliğe sahiptir. Global olarak tek bir örneği çalışır tüm sisteme bağlandığında.
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();
}
}
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)
-
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. -
Tavsiye içinde kullanılan
this
özelliği ile ilgi örneğinin yani nesnesinin adresini görmüş oluyoruz. -
Library
sınıfından oluşturulanlibrary
nesnesinin değerini görmekteyiz. -
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 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)
}
}
}
-
main
metodun içerisinde birleşim noktaları mevcut olduğu için program çalışmaya başladıktan sonra birTraceAspect
ilgi biriminin nesnesi/örneği oluşmamışsa oluşturulur. -
Eşlenen noktadan sonra çalışması istenen bir
Library
sınıfı tipinde parametre alan tavsiye yapısıfinally
bloğuna konuşlanmaktadır. -
(2) de olduğu gibi
doSomething
metodunun çağırılma sonrası gene aynı ilgiye ait nesneden after tavsiye yapısına gidilmektedir. -
Sistemin son basamağında
isOkay
metodunun çağırılmasından sonra tavsiye bileşeni, parametrede yeni yaratılanlibrary2
nesnesini referans almaktadır.
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.
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();
}
}
-
Library
nesnesi doğrultusundaLibrary
sınıfının içinde belirlenen birleşim noktalarında yeniTraceAspect
örnekleri yaratılır.perthis
içindeki pointcut tanımlaması aynı zamanda şu şekilde de yazılabilir:perthis(within(Library))
-
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.
-
Seçilen birleşim noktaları doğrultusunda bu satırda tipin nesnesine bakılarak
TraceAspect
ilgisinden yeni bir örnek türetilir. -
(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.
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
-
Sistemin çalışma akışında görüyoruzki
main
metod içinde çağırılandoSomething
metodunun içine giriliplibrary
nesnesi için ilgi örneği oluşturulmaktadır çünküdoSomething
metodunun içerisinde potansiyel birleşim noktası mevcuttur (Örnek 3, 3.satır). -
Yeni bir ilginin örneği
main
metod içinde çağırılandoNothing
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 seferanotherlibrary
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 dahaLibrary
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.
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.
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)
}
}
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 *
-
Library
sınıfının nesnesi hedef alınarakdoTrace
içerisinde sağlanan şartlara uyan noktalarda yeniTraceAspect
ilgisinin örnekleri oluşturulur. -
Sistemde
Test
sınıfının içerisinde, hedef nesnenin tipiLibrary
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. -
Library
sınıfının nesnesine,millikutuphane
, ait olandoSomething
metodunun çağırılmasında ilk ilgi örneği tanımlanmış olmaktadır ve gerekli tavsiye çalışır. -
(3). satırı takiben,
millikutuphane
nesnesi ile çağırılandoNothing
metodu ile aynı ilgi örneği çalışmaktadır. Yeni ilgi örneği yaratılmıyor çünkü mevcut olan aynı nesne ile devam edilmektedir. -
Library
sınıfının bir diğer yeni nesnesiizmirMilliKutuphane
ile yeni bir ilginin oluşturulur vedoNothing
metodu çağırıldıktan sonra gerekli tavsiye yapısı çalışır. -
Aynı şekilde diğer bir
Library
nesnesinin oluşumu (kent
) sonrası başka birTraceAspect
ilgisinin nesnesi oluşturulur veisOkay
motodunun çağırılmasından sonra tavsiye tetiklenir. -
Runabble
sınıfının çalışmasını sağlayanrun
metodu bu kriterlere uymadığı için sadece program akışında gerekli olan görevini yerine getirir. -
(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ğerStore
sınıfıLibrary
sınıfından türeseydistore.getStoreID();
noktasında yeni bir ilginin daha örneği oluşurdu.
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.
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();
}
}
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 **
-
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ındaTraceAspect
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. -
doSomething
metodu ilk birleşim noktası olmaktadır. Bu nokta ve içerisindekiLibrary
nesnesine ait metod çağırmalarda birer ilgi örneği yaratılır. Bu metodun kontrol akışı izlenirse:isOkay
→doNothing
→doSomething
metodları çalışır ve bu noktalarda yeni ilgiler yaratılır. -
doNothing
metodunun çağırılması ve kontrol akışında içeriğinde uyan diğer birleşim noktalarında yeniTraceAspect
nesnesi oluşmaktadır. IlkisOkay
metodunun çağırımdan oluşan örnekleme gerçekleşir ve daha sonradoNothing
metodunun çağırılmasıyla başka bir örnekleme meydana gelmektedir (TraceAspect@1459877
→TraceAspect@12133b1
) -
Library
sınıfının yeni bir nesnesi,kent
, ile çağırılandoWhat
metodu noktasında,TraceAspect@ea2f77
bilgisine sahip yeni örnekleme gerçekleşmektedir. -
Sistemde pointcut yapısına uyan ve eşlenen nokta
milliKutuphane
nesnesiyle çağırılanisOkay
metodu olmaktadır. Bu metod noktasında da ilgi birimi tekrar yeni bir örneğine sahiptir.
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.
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();
}
}
-
percflow
dan farklı olarak, artık biliyoruzkipercflowbelow
içinde pointcut yapsı ile belirlenen noktalarda tavsiye yordamları çalışmamaktadır. Dolayısıylapercflowbelow
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).
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)
-
main
metod içerisindedoSomething
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. -
main
metod içerisindedoNothing
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. -
main
metod içerisindedoWhat
metodunun çağırılması da aynı şekilde bir birleşim noktası olarak seçildiği için bu noktada yeni birTraceAspect
nesnesi yaratılır ama nesnenin tavsiye yapısı çalışmaz. -
Son ilgi örneği
isOkay
metodunun çağırılmasıyla oluşturulur fakat tavisyesicflowbelow
özelliği devreye girdiği için bu nokta pas geçilir. Kısaca,main
metodundakiLibrary
sınıfına ait nesnelerden çağırılan metodlar bu yapı ile pas geçilir.
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.
...
... 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();
}
}
-
Test
sınıfı için ayrı ilginin yaratılması istenmektedir. Eğerpertypewithin
yapısına sahip ilgi içindeTest
sınıfı dahilinde birleşim noktaları varsa, ilgi nesnesine ait bileşenler bu noktalarda çalışmaktadır. -
pertypewithin
yapısına özel ilgi birimlerinde ara tip tanımlamarında hariç diğer gövdeye sahip elementlerdegetWithinTypeName
metodu çağırılabilir. Bu metod ilgi örneği ile birleşen tipin tam ismini döndürmektedir.
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'
-
Sadece
Test
içerisinde meydana gelecek birleşim noktalarında çalışacak tek tip ilgi örneği yaratılmaktadır.
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, hemaspectOf
hem dethisAspectInstance
if pointcut yapısının içerisinde çalışmakta olup, aralarındaki farkthisAspectInstance
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 geriyeboolean
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)
}
}
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
-
İlgi içinde
this
yerine yazılanTraceAspect.aspectOf()
ya da sadeceaspectOf()
bize global ilginin nesnesini döndürür. -
İlgi içinde
hasAspect()
ya daTraceAspect.hasAspect()
kısaca globalTraceAspect
ilgisinin sistemde genel bir nesnesi olduğunu gösterir. -
Tavsiye yapısı içerisinde
doItAspect
metodunuaspectOf
ile çağırabiliyoruz. Aynı işlemi (4) gösterdiği gibithis
ile de yapabiliriz -
İlginin nesnesinden yararlanarak
doItAspect
metodunu tavsiye içinde çağırıyoruz. İlgi içerisinde (3) ile aynı davranışa sahiptir. -
Belirtildiği gibi statik
aspectOf
sınıfların içerisinde de kullanılmaktadır.main
metodun içerisinde ilginin nesnesine ait olandoItAspect
metodu çağırılıyor.TraceAspcet
ilgisi global olduğu için statik metod parametre almaz. -
Aynı şekilde statik method olan
hasAspect
, başka sınıflar içerisinde de kullanılır. Bu örneğimizdeTest
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)
}
}
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)
-
pertypewithin
yapısı alan ilgi içerisindeaspectOf
metodu bir Java Class nesnesi istemektedir. İlgimiz,Test
ve ondan türeyen sınıflarda çalıştığı için parametre olarakTest
sınıfının yazıyoruz. Çıktı olarakTraceAspect
ilgisininTest
sınıfına ait bir nesnesi olduğunu bize doğrular (true
). -
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ünyesindeTraceAspect
ilgisine bağlı olan nesnedendoItAspect
metodunu çağır demektedir. -
Bu işlemi
hasAspect
metodu içinde yapmaktayız.Test
sınıfı bünyesindeTraceAspect
ilgisine bağlı bir nesnenin olup olmadığını anlıyoruz. -
Son satırda çalışma zamanı karşılaşılan
NoAspectBoundException
istisnası bize kısacaLibrary
sınıfı bünyesindeTraceAspect
ilgisine bağlı bir nesnedendoItAspect
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.
|
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: [TipİmzaDeseni1], [TipİmzaDeseni2], ...; (1)
declare precedence: LoggingAspect, PoolingAspect; (2)
declare precedence: Log*, Pool*; (3)
-
En az iki ilgi biriminin işaret edilmesiyle ilgilerin öncelik sıraları tekrar şekillenir.
-
İki ilginin sıralanması gösterilmektedir. İlgilerin sıralanma düzeni tavsiye yapılarına göre değişmektedir. Örneğin
PoolingAspect
veLoggingAspect
içerisindeki after advice yapısı olursa,PoolingAspect
ilgisinin önceliğiLoggingAspect
ilgisine göre daha yüksektir. Eğer before advice yapısı varsaPoolingAspect
ilgisinin önceliğiLoggingAspect
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çinePoolingAspect
ilgisi yerleşir. -
İ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ümLog
ile başlayan ilgi birimlerinin tavsiye önceliği azaltılıp, tümPool
ile başlayan ilgilere yüksek öncelik verilmektedir.
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();
}
}
Logging concerns... Authentication concerns...
-
Library
sınıfına aitdoNothing
metodunun çağırıldığı noktada hemLogingAspect
hem deAuthenticationAspect
ilgilerindeki after tavsiye yapıları çakışmaktadır. Sistemde ilk loglamanın yapılması istendiği içinOrderAspect
ilgisindedeclare precedence
yapısı kullanılarak bu ilgilerin öncelikleri istenildiği şekilde tekrar düzenlenmektedir. Böylelikle ilklogging
ilgileri sonraauthentication
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.
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();
}
}
Logging concerns... Authentication concerns...
-
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çindeproceed
metodunu çağırarak ayarlanan sırada gereken tavsiyeleri çalıştırmış oluruz.
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)
}
}
PrivilegedAspect :: Id: -1 doing something...
-
Privileged
karaktere sahip ilginin tavsiye yapısı,Main
sınıfınprivate
yapılıid
alanına kolaylıkla erişebiliyor.