The AspectJ programming language An introduction to Aspect- • AspectJ extends the Java programming Oriented Programming with language with constructs in order to support AOP. AspectJ • It is a superset of Java. – Each valid Java program is also a valid AspectJ COMP 303 McGill University program. • It is a general-purpose language (as opposed to Slides based on those from: Constantinos domain-specific). Constantinides • Currently the most notable AOP technology. 2 Behavior of Buffer class A first example: A bounded buffer public class Buffer { • Class Buffer contains public class Buffer { … private String[] BUFFER; public void put (String s) { mutator and accessor int putPtr; // keeps track of puts if (isFull()) methods: int getPtr; // keeps track of gets System.out.println("ERROR: Buffer full"); else { int counter; // holds number of items – Mutators: put(), get() BUFFER[putPtr++] = s; int capacity; counter++; – Accessors: isFull(), Buffer (int capacity) {…} } public boolean isEmpty() {…} isEmpty() } public boolean isFull() {…} public String get() { public void put (String s) {…} if (isEmpty()) public String get() {…} return "ERROR: Buffer empty"; } else { } counter--; return BUFFER[getPtr++]; } } 3 4 } AspectJ language concepts Example: Tracing • Joinpoint: a well-defined event in the execution • Let us display a message before all calls to put() of a program (such as the core functionality and get() inside Buffer. provided by class Buffer). – e.g. the call to method get() inside class Buffer. • This pointcut specifies any call to put() in Buffer, • Pointcut: A collection of joinpoints. taking a String argument, returning void, and – e.g. the execution of all mutator methods inside class with public access. Buffer. • Advice: A block of code that specifies some call(public void Buffer.put(String)) behavior to be executed before/after/around a • A call joinpoint captures an execution event after certain joinpoint. it evaluates a method calls’ arguments, but – e.g. before the call to the body of method get(), before it calls the method itself. display some message. 5 6 1
Identifying joinpoints (cont.) Defining a pointcut • This pointcut specifies all call events to • We define a pointcut named “mutators” that combines both basic pointcut expressions. get() in class Buffer, taking no arguments, returning String, and with public access: pointcut mutators(): call(public void Buffer.put(String)) || call (public String Buffer.get()); call (public String Buffer.get()) 7 8 Defining a pointcut (cont.) Define an advice • We may use logical operators in the definition • An advice must be defined with respect to a pointcut, in of pointcuts in order to combine pointcut this example we define an advice to mutators. expressions: • This is a special type of advice, called “before advice”. As the term suggests, it specifies what must be done just before the event (joinpoint) specified by the pointcut. 1. || (OR operator) • Pointcuts and advice together define composition Matches a joinpoint if either the left pointcut (weaving) rules. expression matches or the right pointcut expression. 2. && (AND operator) Matches a joinpoint only when both the left pointcut before(): mutators() { expression and the right pointcut expression match. System.out.println("------ Mutator method called."); 3. ! (NOT operator) } Matches all joinpoints not specfied by the pointcut 9 10 Advice Providing an aspect definition • An advice associates the code to be executed • Much like a class, an aspect is a unit of modularity. with pointcuts. • It is defined in terms of pointcuts (collections of joinpoints), advice, and ordinary Java fields and • There are three ways to associate an advice methods. with a pointcut: • Pointcuts say which events (joinpoints) to match, and – Before: run just before the pointcut. the advice body says what to execute when it matches. – After: runs just after the pointcut. • May be after normal return, after throwing an exception or after returning either way from a joinpoint. public aspect Tracer { – Around: Runs instead of the pointcut, with the pointcut mutators(): call(public void Buffer.put(String)) || provision for the pointcut to resume normal execution call (public String Buffer.get()); through proceed() (see later) before(): mutators() { System.out.println("------ Mutator method called."); } 11 12 } 2
Tracing the execution Tracing the execution (base program) (after weaving Tracer aspect) ------ Mutator method called. public class BufferDemo { public class BufferDemo { Hello ------ Mutator method called. public static void main(String[] args) { public static void main(String[] args) { there ------ Mutator method called. Buffer buffer = new Buffer(10); Buffer buffer = new Buffer(10); Hello buffer.put("Hello"); buffer.put("Hello"); ------ Mutator method called. buffer.put("there"); buffer.put("there"); there System.out.println(buffer.get()); System.out.println(buffer.get()); System.out.println(buffer.get()); System.out.println(buffer.get()); } } } } public aspect Tracer { pointcut mutators(): call(public void Buffer.put(String)) || call (public String Buffer.get()); before(): mutators() { System.out.println("------ Mutator method called."); } 13 14 } Types of joinpoints Patterns in pointcuts 1. Calls to methods and constructors • Pointcuts use a pattern language to 2. Execution of methods and constructors specify events. 3. Field access • The use of the * character is highly 4. Exception handling overloaded. 5. Class initialization – Using * where a type is expected matches 6. Lexical structure any type. – Using * where an identifier is expected 7. Control flow matches any identifier. 8. Self-target and argument-type – You can also use * within an identifier pattern. 9. Conditional test 15 16 Identifier Patterns Classname patterns • Sometimes we wish to write patterns that • the expression foo* would match any identify a class or a set of classes. identifier starting with “foo”. • To identify a class in the default package • the expression *if* would match any we can just use an identifier pattern. identifier with “if” in it. • We can string together identifier patterns • In general, an identifier pattern can by any to specify packages using “.” and “..”. valid identifier with * characters added to • We can add a “+” to the end of an identifier it. pattern to indicate that we wish to match a class and all of it subclasses. 17 18 3
Specifying classes Specifying packages and classes foo : class foo • MyPackage.foo : the class foo in package MyPackage foo+ : class foo and all of its subclasses • MyPackage.*.foo : the class foo that is in foo* : all classes starting with “foo” some immediate subpackage of MyPackage *foo* : all classes with “foo” in it • MyPackage..foo : the class foo that is in MyPackage or any subpackage of MyPackage. foo*+ : all classes starting with “foo”, and • In package specifications “..” all of their subclasses means . | .*. | .*.*. | … 19 20 Specifying a method/constructor Specifying arguments signature • (*) : one argument, any type Method: • (int) : one argument of type int [modifier_pattern] return_type_pattern • (int,*) : two arguments, first one with classtype_pattern.id_pattern (args_pattern) [throws_pattern] type int • () : no arguments Constructor: • (..) : any number of arguments [modifier_pattern] return_type_pattern • (int,..) : first argument of type int any classtype_pattern.new(args_pattern) number of other arguments [throws_pattern] 21 22 Calls to methods and constructors Calls to methods and constructors (cont.) call (public static void Call to public static myMethod() in call (* MyClass.myMethod* Call to any method with name MyClass.myMethod(String)) MyClass taking a String argument, starting with “myMethod” in (String,..)) return type is void. MyClass and the first argument is of String type. call (void MyClass.myMethod(..)) Call to myMethod() in MyClass call (* *.myMethod(..)) Call to myMethod() in any class in taking any arguments, with void default package. return type, and any access modifiers. call (* MyClass.myMethod(..)) Call to myMethod() in MyClass call (MyClass.new()) Call to the constructor of MyClass taking any arguments, returning taking no arguments. any type. call (* MyClass.myMethod*(..)) Call to any method with name call (MyClass.new(..)) Call to the constructor of MyClass starting with “myMethod” in taking any arguments. MyClass. 23 24 4
Recommend
More recommend