Advanced AspectJ ja AspectJ 5.0 Aleksei Bogdanov a1exey1@ut.ee 05. aprill 2006
Kava AspectJ in Action, peatükk 4 The AspectJ 5 Development Kit Developer's Notebook AOP@Work: AOP and metadata: A perfect match
Advanced AspectJ
Advanced AspectJ Reflective API Aspektide eelnevus (Aspect precedence) Aspektide seostumine (Aspect association) Erindite pehmendamine (Exception softening) Privilegeeritud aspektid (Priveleged aspects)
Reflective API Liidesed, mis tagavad juurdepääsu ühendpunktiga seotud dünaamilisele ja staatilisele infole Dünaamiline info on kättesaadav ka lõikepunktide this(), target() ja args() kaudu Reflective API keerulisem kuid pakub rohkem võimalusi
Ühendpunktiga seotud objektid thisjoinpoint ühendpunkti dünaamiline info (käsitletav objekt, sihtobjekt, meetodi argumendid) thisjoinpointstaticpart ühendpunkti staatiline info (signatuur, tüüp, asukoht koodis) thisenclosingjoinpointstaticpart ümbritseva ühendpunkti staatiline info
org.aspectj.lang.joinpoint liidese meetodid getthis() gettarget() getargs() getstaticpart()
org.aspectj.lang.joinpoint. StaticPart liidese meetodid getkind() getsignature() getsourcelocation()
Reflective API: näide public class Test { public static void main(string[] args) { SavingsAccount account = new SavingsAccount(12456); account.credit(100);
import org.aspectj.lang.*; import org.aspectj.lang.reflect.*; public aspect JoinPointTraceAspect { private int _indent = -1; pointcut tracepoints() :!within(joinpointtraceaspect) &&!call(*.new(..)) &&!execution(*.new(..)) &&!initialization(*.new(..)) &&!staticinitialization(*); before() : tracepoints() { _indent++; println("========= " + thisjoinpoint + " ==========="); println("dynamic join point information:"); printdynamicjoinpointinfo(thisjoinpoint); println("static join point information:"); printstaticjoinpointinfo(thisjoinpointstaticpart); println("enclosing join point information:"); printstaticjoinpointinfo(thisenclosingjoinpointstaticpart);
private void printdynamicjoinpointinfo(joinpoint joinpoint) { println("this: " + joinpoint.getthis() + " Target: " + joinpoint.gettarget()); StringBuffer argstr = new StringBuffer("Args: "); Object[] args = joinpoint.getargs(); for (int length = args.length, i = 0; i < length; ++i) { argstr.append(" [" + i + "] = " + args[i]); println(argstr); private void printstaticjoinpointinfo( JoinPoint.StaticPart joinpointstaticpart) { println("signature: " + joinpointstaticpart.getsignature() + " Kind: " + joinpointstaticpart.getkind()); SourceLocation sl = joinpointstaticpart.getsourcelocation(); println("source location: " + sl.getfilename() + ":" + sl.getline());
========= call(void Account.credit(float)) =========== Dynamic join point information: This: null Target: SavingsAccount@1ad086a Args: [0] = 100.0 Static join point information: Signature: void Account.credit(float) Kind: method-call Source location: Test.java:4 Enclosing join point information: Signature: void Test.main(String[]) Kind: method-execution Source location: Test.java:3 ========= execution(void Account.credit(float)) =========== Dynamic join point information: This: SavingsAccount@1ad086a Target: SavingsAccount@1ad086a Args: [0] = 100.0 Static join point information: Signature: void Account.credit(float) Kind: method-execution Source location: Account.java:12 Enclosing join point information: Signature: void Account.credit(float) Kind: method-execution Source location: Account.java:12
Aspektide eelnevus Võib olla vajalik juhul kui ühele ühendpunktile rakendub rohkem kui üks aspekt Eelnevuse spetsifitseerimata on aspektide rakendamise järjekord juhuslik AspectJ lubab aspektide eelnevust määrata
Eelnevusreeglid
Aspektide eelnevus: süntaks declare precedence : TypePattern1, TypePattern2,..; Näited: declare precedence : AuthenticationAspect, AuthorizationAspect; declare precedence : AuthenticationAspect, *; declare precedence : *, CachingAspect;
Juhiste eelnevus Kui ühele ühendpunktile rakendub mitu sama aspekti juhist, siis esimesena rakendub see juhis mis paikneb aspektis eespool
Aspektide seostumine Üks isend aspektist virtuaalmasina kohta (per virtual machine) (vaikimisi) Üks isend aspektist iga objekti kohta (per object) Üks isend aspektist töövoo kohta (per controlflow) Üks isend aspektist tüübimalli kohta (per type pattern) (AspectJ 5.0)
Aspekti seostumine: süntaks aspect <AspectName> [<associationspecifier>(<pointcut>)] {... aspect body Näide: public abstract aspect CacheManagementAspect perthis(access()) {...
Vaikimisi seostumine: näide public aspect AssociationDemoAspect { public AssociationDemoAspect() { System.out.println("Creating aspect instance"); pointcut accountoperationexecution(account account) : (execution(* Account.credit(..)) execution(* Account.debit(..))) && this(account); before(account account) : accountoperationexecution(account) { System.out.println("JoinPoint: " + thisjoinpointstaticpart + "\n\taspect: " + this + "\n\tobject: " + account);
public class TestAssociation { public static void main(string[] args) throws Exception { SavingsAccount account1 = new SavingsAccount(12245); SavingsAccount account2 = new SavingsAccount(67890); account1.credit(100); account1.debit(100); account2.credit(100); account2.debit(100);
> ajc *.java > java TestAssociation Creating aspect instance JoinPoint: execution(void Account.credit(float)) aspect: AssociationDemoAspect@187aeca object: SavingsAccount@e48e1b JoinPoint: execution(void Account.debit(float)) aspect: AssociationDemoAspect@187aeca object: SavingsAccount@e48e1b JoinPoint: execution(void Account.credit(float)) aspect: AssociationDemoAspect@187aeca object: SavingsAccount@12dacd1 JoinPoint: execution(void Account.debit(float)) aspect: AssociationDemoAspect@187aeca object: SavingsAccount@12dacd1
Kahte tüüpi: perthis() per-object seostumine aspekti isend seostub ühendpunkti objektiga this argumendiga määratud lõikepunktis pertarget() aspekti isend seostub ühendpunkti objektiga target argumendiga määratud lõikepunktis Seostumine toimub hetkel, kui aspekt rakendub antud objektile esimest korda
per-object seostumine: näide public aspect AssociationDemoAspect perthis(accountoperationexecution(account)) { public AssociationDemoAspect() { System.out.println("Creating aspect instance"); pointcut accountoperationexecution(account account) : (execution(* Account.credit(..)) execution(* Account.debit(..))) && this(account); before(account account) : accountoperationexecution(account) { System.out.println("JoinPoint: " + thisjoinpointstaticpart + "\n\taspect: " + this + "\n\tobject: " + account);
> ajc *.java > java TestAssociation Creating aspect instance JoinPoint: execution(void Account.credit(float)) aspect: AssociationDemoAspect@e48e1b object: SavingsAccount@12dacd1 JoinPoint: execution(void Account.debit(float)) aspect: AssociationDemoAspect@e48e1b object: SavingsAccount@12dacd1 Creating aspect instance JoinPoint: execution(void Account.credit(float)) aspect: AssociationDemoAspect@1ad086a object: SavingsAccount@10385c1 JoinPoint: execution(void Account.debit(float)) aspect: AssociationDemoAspect@1ad086a object: SavingsAccount@10385c1
per-control-flow seostumine Kahte tüüpi seostumine: percflow() aspekti isend seostub töövooga (control flow) lõikepunkti rahuldavas ühendpunktis percflowbelow() aspekti isend seostub ühendpunkti järgneva töövooga lõikepunkti rahuldavas ühendpunktis
per-control-flow seostumine: näide public aspect AssociationDemoAspect percflow(accountoperationexecution(account)) { public AssociationDemoAspect() { System.out.println("Creating aspect instance"); pointcut accountoperationexecution(account account) : (execution(* Account.credit(..)) execution(* Account.debit(..))) && this(account); before(account account) : accountoperationexecution(account) (execution(* Account.setBalance(..)) && this(account)) { System.out.println("JoinPoint: " + thisjoinpointstaticpart + "\n\taspect: " + this + "\n\tobject: " + account);
> ajc *.java > java TestAssociation Creating aspect instance JoinPoint: execution(void Account.credit(float)) aspect: AssociationDemoAspect@10385c1 object: SavingsAccount@42719c JoinPoint: execution(void Account.setBalance(float)) aspect: AssociationDemoAspect@10385c1 object: SavingsAccount@42719c Creating aspect instance JoinPoint: execution(void Account.debit(float)) aspect: AssociationDemoAspect@30c221 object: SavingsAccount@42719c JoinPoint: execution(void Account.setBalance(float)) aspect: AssociationDemoAspect@30c221 object: SavingsAccount@42719c
Creating aspect instance JoinPoint: execution(void Account.credit(float)) aspect: AssociationDemoAspect@119298d object: SavingsAccount@f72617 JoinPoint: execution(void Account.setBalance(float)) aspect: AssociationDemoAspect@119298d object: SavingsAccount@f72617 Creating aspect instance JoinPoint: execution(void Account.debit(float)) aspect: AssociationDemoAspect@1e5e2c3 object: SavingsAccount@f72617 JoinPoint: execution(void Account.setBalance(float)) aspect: AssociationDemoAspect@1e5e2c3 object: SavingsAccount@f72617
per-type-pattern seostumine pertypewithin() aspekti isend seostub tüübiga, mis rahuldab etteantud tüübimalli Kasulik juhul, kui on vaja säilitada olekut iga tüübi jaoks mingist tüüpide hulgast Näide: public aspect InstanceTracking pertypewithin(org.xyz..*) {...
Erindite pehmendamine Annab võimaluse käsitleda ühendpunkti poolt tekitatud kontrollitav erindit (checked exception) kontrollimata erindina (unchecked exception) Kaob vajadus erindit töödelda või panna see meetodi spetsifikatsiooni Erindite töötlemise ühte kohta koondamine
Erindi pehmendamine: süntaks declare soft : <ExceptionTypePattern> : <pointcut>; Näide: declare soft: RemoteException : call(* Foo.*(..));
Erindi pehmendamine: näide import java.rmi.remoteexception; public class TestSoftening { public static void main(string[] args) { TestSoftening test = new TestSoftening(); test.perform(); public void perform() throws RemoteException { throw new RemoteException(); public aspect SofteningTestAspect { declare soft : RemoteException : call(void TestSoftening.perform());
import java.rmi.remoteexception; public class TestSoftening { public static void main(string[] args) { TestSoftening test = new TestSoftening(); try { test.perform(); catch (RemoteException ex) { throw new SoftException(ex); public void perform() throws RemoteException { throw new RemoteException();
Privilegeeritud aspektid Annavad võimaluse Java juurdepääsu reeglitest üle saada Juurdepääs klassi private väljadele Süntaks: privileged public aspect PrivilegeTestAspect {...
AspectJ 5
Mis on AspectJ 5? Olulised muudatused keeles ja vahendites Java 5 toetamine AspectJ võimaluste laiendamine
AspectJ 5 Annotatsioonid (Annotations) Klassimallid (Generics) per-type-pattern seostumine Laadimisaegne põimimine (load-time weaving) Muud võimalused
Annotatsioonid Programmi liikmete metainfo väljendamiseks Saab rakendada pakettide ja tüüpide deklaratsioonidele, konstruktoritele, meetoditele, väljadele, parameetritele ja muutujatele Näide: @Authenticated(role="supervisor") public void somemethod() {...
Annotatsioonid ja AspectJ AspectJ lubab lisada annotatsioone aspektidele, meetoditele, klassi- ja isendiväljadele, konstruktoritele, parameetritele ja juhistele Võimalus kasutada annotatsioone ühendpunkti sobitamisel
Elementide mallid Nime järgi: @<qualified-name> @Immutable @Foo @Goo Malli järgi: @(<type-pattern>) @(Foo Goo) @(org.xyz..*)
Tüüpide mallid (@Immutable *) ((@Immutable Foo+) Goo) (@Immutable @NonPersistent org.xyz..*)
Signatuuride mallid @SensitiveData * * @SensitiveData List org.xyz..*.* @Oneway * *(..) * *.*(@Immutable *,..)
Dünaamiline kontekst @this @target @args @within @withincode @annotation call(* *(..)) && @target(classified)
Näited within(@secure *) call(@oneway * *(..)) set(@cachable * *) pointcut insidecriticalmethod(critical c) : @withincode(c); declare parents : (@Secured *) implements SecuredObject; declare precedence : (@Security *),*;
Annotatsioonide kasutamine Metaandmete esitamine @Transactional(kind=Required) public void credit(float amount) {... Lihtsamini hallatavad lõikepunktid public pointcut transactedops() : execution(@transactional * *.*(..));
Annotatsioonide kasutamine Annotatsiooniga varustamine (supplying annotation) declare annotation : * Account.*(..) : @Authenticated(permission="banking"); Annotatsioonide tarbimine (consuming annotation) pointcut transactedops() : execution(@transactional * *.*(..));
Mitmedimensionaalne signatuur
AspectJ annotatsioonid @Aspect public class Foo { @Aspect("perthis(execution(* abc..*(..)))") public class Foo { @Pointcut("call(* *.*(..))") void anycall() { @Before("call(* org.aspectprogrammer..*(..)) && this(foo)") public void callfromfo{ System.out.println("Call from Foo");
Klassimallid (generics) public interface List<E> { Iterator<E> iterator(); void add(e anitem); E remove(e anitem);
Klassimallide parameetrid class Foo<T> {... class Foo<T,S> {... class Foo<T extends Number> {... class Foo<T extends Number & Comparable> {...
Klassimallide väärtustamine List<String> List<?> List<? extends Number> List<? super Double>
Klassimallid ja AspectJ Klassimallide tugi lõikepunktide ja aspektide defineerimisel Võimalus luua abstraktsete aspektide klassimalle Sobitamine lõikepunkti avaldises toimub tüübi kustutamise (erasure) põhimõttel.
Näide class C { public void foo(list<? extends Number> listofsomenumbertype) { public void bar(list<?> listofsometype) { public void goo(list<double> listofdoubles) {
execution(* C.*(List)) execution(* C.*(List<?>)) execution(* C.*(List<? extends Object+>)) args(list<double>)
Aspektide klassimallid (generic aspects) Saab defineerida ainult abstraktsete aspektide jaoks Näide: public abstract aspect ParentChildRelationship<P,C> {...
Lisaks AspectJ tugi muudele uuendustele: Autoboxing ja unboxing Varargs Covariance Loendid (enumerations)
Laadimisaegne põimimine (load-time weaving) Põimimine lükatakse edasi kuni klassi laadimiseni virtuaalmasinasse "weaving class loader"
Küsimused