540 likes | 606 Views
Learn about crosscutting concerns, problems, solutions, consequences, and the AOP approach in programming. A detailed guide on dynamic vs. static crosscutting with code examples and language dynamics explained.
E N D
Construction du journal dans Tomcat • Le rouge montre les lignes de code qui traitent du logging • Très mal modularisé
Le code traite de plusieurs aspects • class Fraction { int numerator; int denominator; ... public Fraction multiply(Fraction that) {traceEnter("multiply", new Object[] {that});Fraction result = new Fraction( this.numerator * that.numerator, this.denominator * that.denominator);result =result.reduceToLowestTerms();traceExit("multiply", result); return result;} ...}
Préoccupations • Préoccupations métier : • Effectuer des paiements : débiter un montant d'un compte défini • Préoccupations techniques : • Traces • Intégrité de la transaction • Identification / authentification • Sécurité (confidentialité) • Performance • etc.
Dispersion / entrelacement des préoccupations • Chaque objet métier gère ses propres contraintes techniques (à son niveau) : • les préoccupations sont dispersées / entrelacées • Les applications sont plus difficiles à : • Concevoir / coder • Comprendre • Maintenir • Faire évoluer...
Symptômes • L’embrouillement du code • Les objets métiers interagissent simultanément avec de nombreuses préoccupations techniques • Présence simultanée d’éléments de chaque préoccupation dans le code • L’étalement du code • Les préoccupations entrelacées, s’étalent sur de nombreux modules. • Leur implémentation s’étale elle aussi sur de nombreux objets
Conséquences • Redundant code • Same fragment of code in many places • Difficult to reason about • Non-explicit structure • The big picture of the tangling isn’t clear • Difficult to change • Have to find all the code involved... • ...and be sure to change it consistently • ...and be sure not to break it by accident • Inefficient when crosscuting code is not needed
Solutions actuelles • mix-in classes • Une classe qui fournit des fonctionnalités à être héritées par une autre classe, mais qui n’a pas de raisons d’être en soi. • Inheriting from a mixin is not a form of specialization but is rather a means to collect functionality. • design patterns • Exemple Visitor et Template Method permettent de différer l’implémentation • domain-specific solutions • frameworks and application servers, • let developers address some crosscutting concerns in a modularized way. • The Enterprise JavaBeans (EJB) architecture, for example, addresses crosscutting concerns such as security, administration, performance, and container-managed persistence.
Introduction • What is a crosscutting concern? • Behavior that cuts across the typical divisions of responsibility, such as logging or debugging • A problem which a program tries to solve. • Aspects of a program that do not relate to the core concerns directly, but which proper program execution nevertheless requires.
LanguageDynamic VS Static crosscutting • Dynamic crosscutting • define additional behavior to run at certain well-defined points in the execution of the program • Static crosscutting • modify the static structure of a program • adding new methods, • implementing new interfaces, • modifying the class hierarchy, • etc.
Programmation par aspects • Implémenter des préoccupations de façon indépendante • Combiner ces implémentation pour former le système final • L’AOP est l’évolution logique de la programmation orientée objet
Etapes de développement de l’AOP • Identifier le préoccupations métier (classes) et techniques (aspects) • Implémenter chaque préoccupation séparément • Tisser les différentes préoccupations
Example I • A pointcut named move that chooses various method calls: • pointcut move(): call(void FigureElement.setXY(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); • Advice (code) that runs before the move pointcut: • before(): move() { System.out.println("About to move");} • Advice that runs after the move pointcut: • after(): move() { System.out.println("Just successfully moved");}
LanguageJoin Points • Well-defined points in the execution of a program: • Method call, Method execution • Constructor call, Constructor execution • Static initializer execution • Object pre-initialization, Object initialization • Field reference, Field set • Handler execution • Advice execution
Field-set “Point.x” Field-set “Point.y” Method-call “Point.incrXY(..)” Method-execution “Point.incrXY(..)” Field-set “Point.y” Field-set “Point.x” Constructor-execution “Point(..)” Preinitialization “Point(..)” Initialization “Point(..)” LanguageJoin Points public class Test{ public static void main(String[] args) { Point pt1 = new Point(0,0); pt1.incrXY(3,6); } } Method-execution “Test.main(..)” Constructor-call “Point(..)” Staticinitialization “Point._clinit_” public class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } public void incrXY(int dx, int dy){ x=+dx; y=+dy; } … }
Join points • A join point is a well-defined point in the program flow • We want to execute some code (“advice”) each time a join point is reached • We do not want to clutter up the code with explicit indicators saying “This is a join point” • AspectJ provides a syntax for indicating these join points “from outside” the actual code • A join point is a point in the program flow “where something happens” • Examples: • When a method is called • When an exception is thrown • When a variable is accessed
Example pointcut designators I • When a particular method body executes: • execution(void Point.setX(int)) • When a method is called: • call(void Point.setX(int)) • When an exception handler executes: • handler(ArrayOutOfBoundsException) • When the object currently executing (i.e. this) is of type SomeType: • this(SomeType)
Example pointcut designators II • When the target object is of type SomeType • target(SomeType) • When the executing code belongs to class MyClass • within(MyClass) • When the join point is in the control flow of a call to a Test's no-argument main method • cflow(call(void Test.main()))
Pointcut designator wildcards • It is possible to use wildcards to declare pointcuts: • execution(* *(..)) • Chooses the execution of any method regardless of return or parameter types • call(* set(..)) • Chooses the call to any method named set regardless of return or parameter type • In case of overloading there may be more than one such set method; this pointcut picks out calls to all of them
Pointcut designators based on types • You can select elements based on types. For example, • execution(int *()) • Chooses the execution of any method with no parameters that returns an int • call(* setY(long)) • Chooses the call to any setY method that takes a long as an argument, regardless of return type or declaring type • call(* Point.setY(int)) • Chooses the call to any of Point’s setY methods that take an int as an argument, regardless of return type • call(*.new(int, int)) • Chooses the call to any classes’ constructor, so long as it takes exactly two ints as arguments
Pointcut designator composition • Pointcuts compose through the operations or (“||”), and (“&&”) and not (“!”) • Examples: • target(Point) && call(int *()) • Chooses any call to an int method with no arguments on an instance of Point, regardless of its name • call(* *(..)) && (within(Line) || within(Point)) • Chooses any call to any method where the call is made from the code in Point’s or Line’s type declaration • within(*) && execution(*.new(int)) • Chooses the execution of any constructor taking exactly one int argument, regardless of where the call is made from • !this(Point) && call(int *(..)) • Chooses any method call to an int method when the executing object is any type except Point
Pointcut designators based on modifiers • call(public * *(..)) • Chooses any call to a public method • execution(!static * *(..)) • Chooses any execution of a non-static method • execution(public !static * *(..)) • Chooses any execution of a public, non-static method • Pointcut designators can be based on interfaces as well as on classes
Kinds of advice • AspectJ has several kinds of advice; here are some of them: • Before advice runs as a join point is reached, before the program proceeds with the join point • After advice on a particular join point runs after the program proceeds with that join point • after returning advice is executed after a method returns normally • after throwing advice is executed after a method returns by throwing an exception • after advice is executed after a method returns, regardless of whether it returns normally or by throwing an exception • Around advice on a join point runs as the join point is reached, and has explicit control over whether the program proceeds with the join point
Example II, with parameters • You can access the context of the join point: • pointcut setXY(FigureElement fe, int x, int y): call(void FigureElement.setXY(int, int)) && target(fe) && args(x, y); • after(FigureElement fe, int x, int y) returning: setXY(fe, x, y) { System.out.println(fe + " moved to (" + x + ", " + y + ").");}
Introduction • An introduction is a member of an aspect, but it defines or modifies a member of another type (class). With introduction we can • add methods to an existing class • add fields to an existing class • extend an existing class with another • implement an interface in an existing class • convert checked exceptions into unchecked exceptions
Example introduction • aspect CloneablePoint { declare parents: Point implements Cloneable; declare soft: CloneNotSupportedException: execution(Object clone()); Object Point.clone() { return super.clone(); }}
Approximate syntax • An aspect is: aspect nameOfAspect { body } • An aspect contains introductions, pointcuts, and advice • A pointcut designator is: when(signature) • The signature includes the return type • The “when” is call, handler, execution, etc. • A named pointcut designator is:name(parameters): pointcutDesignator • Advice is:adviceType(parameters): pointcutDesignator { body } • Introductions are basically like normal Java code
Example aspect I • aspect PointWatching { private Vector Point.watchers = new Vector(); public static void addWatcher(Point p, Screen s) { p.Watchers.add(s); } public static void removeWatcher(Point p, Screen s) { p.Watchers.remove(s); } static void updateWatcher(Point p, Screen s) { s.display(p); }// continued on next slide
Example aspect II • // continued from previous slidepointcut changes(Point p): target(p) && call(void Point.set*(int)); after(Point p): changes(p) { Iterator iter = p.Watchers.iterator(); while ( iter.hasNext() ) { updateWatcher(p, (Screen)iter.next()); } }}
Références • The AspectJTM Programming Guide • http://www.eclipse.org/aspectj/doc/released/progguide/index.html • I want my AOP! • http://www.javaworld.com/javaworld/jw-01-2002/jw-0118-aspect.html • Aspect-Oriented Programming with AspectJ™ • http://dolphin.c.u-tokyo.ac.jp/~kazu0/aspectj/doc/tutorial/aspectj-tutorial.pdf • www.cs.cmu.edu/~aldrich/courses/819/slides/aspectj.ppt • http://www.eclipse.org/ajdt/demos/HelloWorldAspectJ.html
LanguagePointcuts • A set of join point, plus, optionally, some of the values in the execution context of those join points. • Can be composed using boolean operators || , && • Matched at runtime
LanguageAdvice • Method-like mechanism used to declare that certain code should execute at each of the join points in the pointcut. • Advice: • before • around • after • after • after returning • after throwing
LanguageAdvice • Method-like mechanism used to declare that certain code should execute at each of the join points in the pointcut. • Advice: • before • around • after • after • after returning • after throwing
LanguagePointcut parameters and thisJoinPoint thisJoinPoint • Simple reflective access to information about the current join point. Notice that this is very useful for debugging and tracing purposes. before(): call(void Point.setX(int)){ if(((Integer)thisJoinPoint.getArgs()[0]).intValue()>10) System.out.println("The value is too big !"); else System.out.println("x value of ” +thisJoinPoint.getTarget() +" will be set to” +thisJoinPoint.getArgs()[0]); }
LanguageWildcards and cflow • Wildcards • call( * Point. *(..)) • call( public * com.xerox.scanner.*.*(..)) • call( * Point.get*())
LanguageWildcards and cflow • Control-flow • pointcut moveContext(): cflow(move()) • picks out each join point that occurs in the dynamic context of the join points picked out by move().