advanced aspectj ja aspectj 5 - ut · advanced aspectj reflective api aspektide eelnevus (aspect...
TRANSCRIPT
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@1ad086aArgs: [0] = 100.0Static join point information:Signature: void Account.credit(float) Kind: method-callSource location: Test.java:4Enclosing join point information:Signature: void Test.main(String[]) Kind: method-executionSource location: Test.java:3
========= execution(void Account.credit(float)) ===========Dynamic join point information:This: SavingsAccount@1ad086a Target: SavingsAccount@1ad086aArgs: [0] = 100.0Static join point information:Signature: void Account.credit(float) Kind: method-executionSource location: Account.java:12Enclosing join point information:Signature: void Account.credit(float) Kind: method-executionSource 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üntaksdeclare 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 control-
flow)
● Üks isend aspektist tüübimalli kohta (per type pattern) (AspectJ 5.0)
Aspekti seostumine: süntaksaspect <AspectName> [<association-specifier>(<Pointcut>)] {
... aspect body}
Näide:
public abstract aspect CacheManagementAspect perthis(access()) {
... }
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); }}
Vaikimisi seostumine: näide
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 TestAssociationCreating aspect instanceJoinPoint: execution(void Account.credit(float))
aspect: AssociationDemoAspect@187aecaobject: SavingsAccount@e48e1b
JoinPoint: execution(void Account.debit(float))aspect: AssociationDemoAspect@187aecaobject: SavingsAccount@e48e1b
JoinPoint: execution(void Account.credit(float))aspect: AssociationDemoAspect@187aecaobject: SavingsAccount@12dacd1
JoinPoint: execution(void Account.debit(float))aspect: AssociationDemoAspect@187aecaobject: SavingsAccount@12dacd1
per-object seostumineKahte tüüpi:● perthis()aspekti isend seostub ühendpunkti objektiga this
argumendiga määratud lõikepunktis● pertarget()aspekti isend seostub ühendpunkti objektiga target
argumendiga määratud lõikepunktisSeostumine toimub hetkel, kui aspekt rakendub
antud objektile esimest korda
per-object seostumine: näidepublic 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 TestAssociationCreating aspect instanceJoinPoint: execution(void Account.credit(float))
aspect: AssociationDemoAspect@e48e1bobject: SavingsAccount@12dacd1
JoinPoint: execution(void Account.debit(float))aspect: AssociationDemoAspect@e48e1bobject: SavingsAccount@12dacd1
Creating aspect instanceJoinPoint: execution(void Account.credit(float))
aspect: AssociationDemoAspect@1ad086aobject: SavingsAccount@10385c1
JoinPoint: execution(void Account.debit(float))aspect: AssociationDemoAspect@1ad086aobject: SavingsAccount@10385c1
per-control-flow seostumineKahte 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äidepublic 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 TestAssociationCreating aspect instanceJoinPoint: execution(void Account.credit(float))
aspect: AssociationDemoAspect@10385c1object: SavingsAccount@42719c
JoinPoint: execution(void Account.setBalance(float))aspect: AssociationDemoAspect@10385c1object: SavingsAccount@42719c
Creating aspect instanceJoinPoint: execution(void Account.debit(float))
aspect: AssociationDemoAspect@30c221object: SavingsAccount@42719c
JoinPoint: execution(void Account.setBalance(float))aspect: AssociationDemoAspect@30c221object: SavingsAccount@42719c
Creating aspect instanceJoinPoint: execution(void Account.credit(float))
aspect: AssociationDemoAspect@119298dobject: SavingsAccount@f72617
JoinPoint: execution(void Account.setBalance(float))aspect: AssociationDemoAspect@119298dobject: SavingsAccount@f72617
Creating aspect instanceJoinPoint: execution(void Account.debit(float))
aspect: AssociationDemoAspect@1e5e2c3object: SavingsAccount@f72617
JoinPoint: execution(void Account.setBalance(float))aspect: AssociationDemoAspect@1e5e2c3object: 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üntaksdeclare soft : <ExceptionTypePattern> :
<pointcut>;
Näide:
declare soft: RemoteException : call(* Foo.*(..));
Erindi pehmendamine: näideimport 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õikepunktidpublic 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äideclass 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