Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

AspectJ: Aspect Oriented Programming for Java

No description
by

Phil Hayward

on 16 March 2013

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of AspectJ: Aspect Oriented Programming for Java

Phil Hayward
Clearwater Analytics
phayward@clearwateranalytics.com AspectJ: Aspect Oriented Programming for Java Aspect Oriented Programming (AOP) Overview References The AspectJ Programming Guide
http://www.eclipse.org/aspectj/doc/released/progguide/index.html

The AspectJ 5 Development Kit Developer's Notebook
http://www.eclipse.org/aspectj/doc/released/adk15notebook/index.html Vocabulary Annotation: a Java language construct to provide code metadata.

Concern: a distinct, cohesive area of functionality.

Crosscutting concern: an area of functionality that cannot be easily implemented in traditional abstractions because it "cuts across" multiple abstractions. This is typically a secondary functionality, such as logging.

Aspect: encapsulation of code for a given concern, somewhat like a class. Vocabulary Part II Join point: the point in object-oriented code where the aspect code should be invoked.

Point cut: the definition of a point in existing code where aspect code should be invoked.

Advice: aspect code you want to apply to an existing code base.

Inter-type declaration: a declaration that cuts across classes and heirarchies. Similar to an interface, except the implementation is in the aspect, and does not need to be added to each affected class. Questions? Integration with Maven Maven in a nutshell: build management tool for Java Example Aspects What is it? Why do we care? There are issues or concerns that are not well defined by traditional object oriented programming. Aspect oriented programming is a way of modularizing these cross-cutting concerns, much like object oriented programming is a way of modularizing common concerns. Profiling and Logging Tracing Tracing is often used to increase the visibility of the internals of a program module. Our first sample will simply display a trace when a specific method is called. Contract Enforcement Pre- and Post-Conditions Change Monitoring import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class SimpleTrace {
@Pointcut("call(void com.clearwateranalytics.aspectjdemo.App.sayHello(String))")
void tracedCall() {}

@Before("tracedCall()")
public void displayTrace(JoinPoint thisJoinPoint) {
System.out.println("Entering: " + thisJoinPoint +" at "+thisJoinPoint.getSourceLocation());
}
} I am using the annotation style syntax, which allows me to use AspectJ in any modern Java IDE without warnings. There are some functional differences between the AspectJ language syntax and the annotation syntax. You can find details in the AspectJ 5 Development Tookit Developer's Notebook, Chapter 9. @Aspect
public class BasicProfiler {
int totalCount = 0;
int recursiveCount = 0;

@Before("call (void com.clearwateranalytics.aspectjdemo.App.doStuff(int))")
public void incrementTotalCount() {
totalCount++;
}

@Before("call (void com.clearwateranalytics.aspectjdemo.App.doStuff(int)) &&
cflow(execution (void com.clearwateranalytics.aspectjdemo.App.doStuff(int)))")
public void incrementRecursiveCount() {
recursiveCount++;
}

@After("call (void com.clearwateranalytics.aspectjdemo.App.doStuff(int)) &&
!cflow(execution (void com.clearwateranalytics.aspectjdemo.App.doStuff(int)))")
public void displayStats() {
System.out.println(String.format("Total: %d\tRecursive: %d",totalCount,recursiveCount));
}
} The difference between call() and execution() is whether the control flow has passed to the target method yet.

call(method) join points are in the calling method, while execution(method) join points are in the target method.

Note that you could easily use the logging facility of your choice instead of System.out. @Aspect
public class RangeCheck {

@Before("call (int com.clearwateranalytics.aspectjdemo.App.addInts(int,int)) && args(a,b)")
public void checkAddIntsInput(int a, int b) {
if (a < 0 || b < 0)
throw new IllegalArgumentException("input to addInts must be non-negative integers");
}

@AfterReturning(pointcut="call (int com.clearwateranalytics.aspectjdemo.App.addInts(int,int))",returning="rval")
public void checkAddIntsOutput(int rval) {
if (rval < 0)
throw new OverflowException("Integer overflow in addInts");
}
} Pre- and post-condition checking requires access to arguments and return values in an advice. Consider an object registry that is designed such that only well-known factory methods should add to it. Contract enforcement can ensure this design is followed. Make sure you pay attention to the return type in the pointcut. @Aspect
public class RegistrationProtection {
@Pointcut("call(void com.clearwateranalytics.aspectjdemo.Registry.register(..))")
void register() {}

@Pointcut("withincode(static * com.clearwateranalytics.aspectjdemo.ObjectFactory.make(..))")
void canRegister() {}

@Before("register() && !canRegister()")
public void illegalRegistration(JoinPoint thisJoinPoint) {
throw new IllegalAccessException("Illegal registration at " +
thisJoinPoint.getSourceLocation());
}
} .. is a parameter wildcard that matches any parameter signature (including empty) @Aspect
public class ChangeMonitor {
public interface Monitorable {
public void setDirty();
public boolean testAndReset();
}

@DeclareMixin("com.clearwateranalytics.aspectjdemo.App") //Add property and methods to the class
public static Monitorable createMonitorable() {
return new Monitorable() {
private boolean dirty = false;

public void setDirty() {
dirty = true;
}

public boolean testAndReset() {
boolean rval = dirty;
dirty = false;
return rval;
}
};
}

@After("execution (void com.clearwateranalytics.aspectjdemo.App.set*(..)) && this(app)")
public void setDirtyFlag(App app) {
((Monitorable)app).setDirty();
}
} In this example, we actually add a new property and some new methods to the App class.

For singleton dirty flags, the flag variable can be private to the aspect. AspectJ rewrites pointcuts into an optimal form for pointcut matching. The fastest tests are performed first, which allows AspectJ to quickly discard join points that don't match. That means you don't have to worry about the order they're specified in - you just need to make sure you include enough to give AspectJ something to work with.

Scoping designators: select a group of join points based on scope. For example: within, withincode
Kinded designators: select a particular kind of join point. For example: execution, get, set, call, handler
Contextual designators: match (and optionally bind) based on context. For example: this, target

Try to include at least the first two types (scoping and kinded). The contextual designators are typically only used to bind the context for use in the advice.

Scoping designators are very fast to match - always include one if possible.

Supplying either just a kinded designator or just a contextual designator will work but could affect weaving performance (time and memory used) due to all the extra processing and analysis. @Aspect
public class RegistrationProtection {
@Pointcut("call(void com.clearwateranalytics.aspectjdemo.Registry.register(..))")
void register() {}

@Pointcut("withincode(static * com.clearwateranalytics.aspectjdemo.ObjectFactory.make(..))")
void canRegister() {}

@DeclareError("register() && !canRegister()")
static final String illegalRegistrationMessage = "Illegal registration";
} Writing Good Pointcuts a.k.a. making compilation not quite so slow Contract Enforcement, Improved The previous example works, but it only catches problems at run time. We can do better. Using DeclareError causes the AspectJ compiler to throw an error during the build process. The DeclareWarning annotation raises a warning instead of an error. Prevent the standard Java compiler from building aspects <project ...>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<excludes>
<exclude>src/main/java/path/to/aspects/*.java</exclude>
</excludes>
</configuration>
</plugin>
...
</plugins>
...
</build>
...
</project> Include the AspectJ runtime component <project>
...
<dependencies>
...
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
...
</dependencies>
...
</project> Weaving aspects - local code only ...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.4</version>
<configuration>
<aspectDirectory>src/main/java/path/to/aspects</aspectDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal> <!-- use this goal to weave all your main classes -->
</goals>
</execution>
</executions>
</plugin>
... Weaving into external libraries ...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
...
<configuration>
...
<weaveDependencies>
<weaveDependency>
<groupId>com.some.project.group</groupId>
<artifactId>external-library-name</artifactId>
</weaveDependency>
</weaveDependencies>
</configuration>
</plugin>
... ...
<plugin>
<artifactId>maven-war-plugin</artifactId>
...
<configuration>
<packagingExcludes>
WEB-INF/lib/external-library-name*.jar,
WEB-INF/lib/external-library-two*.jar
</packagingExcludes>
...
</configuration>
</plugin>
... Excluding woven libraries Excluding woven libraries for "live deploy" webapp testing ...
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<delete>
<fileset dir="${project.build.directory}/${project.name}/WEB-INF/lib">
<include name="external-library-name*.jar" />
</fileset>
</delete>
</target>
</configuration>
</execution>
</executions>
</plugin>
... Change monitoring Contract enforcement Pre- and post-condition enforcement Profiling and logging Tracing Build Process 1) Write awesome OO + AO code
2) Compile OO code as usual (i.e. javac)
a) Don't compile aspect code
3) Compile AO code
a) Compile aspects
b) Find join points (we need to where to find OO code)
c) Weave aspects into OO code
4) Package modified classes Profiling, Take 2 @Aspect
public class AroundDemo {

@Around("call (void com.clearwateranalytics.aspectjdemo.App.doStuff(int))")
public void profileDoStuff(ProceedingJoinPoint thisJoinPoint) {
long start = System.currentTimeMillis();
thisJoinPoint.proceed();
System.out.printf("Duration of doStuff: %d ms\n",System.currenTimeMillis() - start);
}

@Pointcut("call (int com.clearwateranalytics.aspectjdemo.App.addInts(int,int)) && args(a,b)")
void addition(int a, int b){}

@Around("addition(a,b)")
public Object doAddition(ProceedingJoinPoint thisJoinPoint, int a, int b) {
if ( a+b % 2 == 0 )
return ( a + b ) / 2;
else
return thisJoinPoint.proceed(new Object[] { a, b });
}
Full transcript