Two Types of Weaving in AOP
Build Time Weaving
is more of a style of a regular programming. Aspects are typically as
an integral part of target application. It is used to achieve a
greater Separation of Concerns, where it cannot be easily reached by
ordinary design patterns, to keep code simple and readable. Typical
usage – unobtrusive logging, declarative transaction management,
transparent caching. These things may “pollute” main code from a
design point of view or compromise speed when even a few surplus
condition matter. You can easily remove all logging commands as a
mater of changing a single build configuration option, without a
single change in source code.
AspectJ distinguishes
Compile-time weaving (source code level) and
Post-compile weaving (binary class weving). I
dared to put them in one category for purpose of this article.
The Load Time Weaving (LTW) is rather a
technique for ad hoc modification of unsuspecting target
application in runtime. You “hack in” to the target application.
Such Aspects are developed separately from target code. Often without
having access to the original source code. It is used only for
specific tasks, like method tracing, performance monitoring.
Imagine this situation. You have build application,
a JAR or WAR, it passed whole formal releasing process, not a trivial
thing in big corporations, it was successfully deployed. But then you
suspect an issue. Unfortunately, none put any logging to the
suspected part of the application. Time is crucial, rebuild is not an
option. LTW is to rescue. Write simple advice, targeted to specific
package or class, log internal states. Still, the server needs to be
restarted, start up parameters added to include the aspect related,
but still better then full rebuild and redeployment.
Or this scenario. You need to trace used classes do
do some serious cleaning. Your application is still in development,
in environment you control. You could rebuild it using regular build
time weaver with
ajc
compiler. However, lets assume it is a legacy application, mature,
with complex build, chain of build tools, mixture of JVM languages,
Java and Groovy, not necessary a Maven build, figuring out where to
plug a
jc
compiler and having the confidence all intended classes were really
advised, it may be tricky business. Time consuming. Much simpler and
safer is to use LTW.
For more read here.
Code based style versus annotation based style
AspectJ supports two styles, the
original code based, and from version 1.5 also annotation based
style. TraceAgent code uses annotation based style. You can clearly see
@Pointcut
,
@After
,
@Before
,
@Around
,
@Aspect
from package org.aspectj.lang.annotation.
After in source code of
TraceAllAgent
class.
Benefit is, you don't need any special compiler or IDE plugin. Just
core Java and basic Eclipse JDT. Disadvantage is, it does not
syntactically checks the pointcut definitions, there is no indication
which classes are affected by the aspects. Everything is evaluated
only in runtime. AspectJ has excellent plugin – AJDT
or Eclipse plugin for AspectJ. It is actively developed, currently in
version 2.2.1.
See video demonstrations
what it can do. If you plan to deal with aspects more intensively, it
would pay off to invest time and effort and set up you IDE and tool
chain accordingly and use aspect classes (*.aj files). For our all
method tracing agent, a one off tool, it is no brainer to pick
annotation based rules definition.
The use of the
@AspectJ
annotations means that application can be compiled by a regular Java
5 compiler, and subsequently woven by the AspectJ weaver (for
example, as an additional build stage, or as late as class
load-time).
Unfortunately annotation based style is much less documented. Most available examples on internet use code based style. The official developers guide - The
AspectJ Programming Guide (link)
– barely mentions annotation style. The best (if not only) documentation to @AspectJ annotations are in the older guide The AspectJ 5 Development Kit
Developer's Notebook, see chapter chapter 9 there:
http://www.eclipse.org/aspectj/doc/released/adk15notebook/ataspectj-pcadvice.html
http://www.eclipse.org/aspectj/doc/released/adk15notebook/ataspectj-pcadvice.html
This "developers notebook" is still far more complete documentation then Programming Guide. As a preffered source of information is suggested even by AspectJ authorities.
Code based style versus annotation based style – comparison
Code based style. Note the aspect keyword instead usuall class.
public
aspect Foo {
pointcut
listOperation() : execute(* java.util.List.*(..));
pointcut
anyUtilityCall() : execute(* my.home.util..*(..));
before()
: listOperation()
{
System.out.println(...);
}
after()
: anyUtilityCall() {
System.out.println(...);
}
}
Equivalent in annotation based style, using @AspectJ annotations.
@Aspect
public class Foo {
@Pointcut("execute(*
java.util.List.*(..))")
void
listOperation() {}
@Pointcut("execute(*
my.home.util..*(..))")
void
anyUtilityCall() {}
@Before("listOperation()")
public
void logAllMethodsOnAList() {
//
advice method name is can be
anything
System.out.println(...);
}
@After("anyUtilityCall()")
public
void logUtilityMethods() {
System.out.println(...);
}
}
In most situations you can simplify this even more:
@Aspect
public
class Foo {
@Before(pointcut
= "execute(* java.util.List.*(..))")
public
void logAllMethodsOnAList() {
//
advice method name is can be
anything
System.out.println(...);
}
@After(pointcut
= "execute(* my.home.util..*(..))")
public
void logUtilityMethods() {
System.out.println(...);
}
}
Advice methods - those annotated with @Before, @After etc. - can have
arguments. You can handle (selected) arguments in this way, as a
proper named arguments, or some other runtime information, like
reference to calling instance.
Or you can add
JoinPoint
as an advice argument as in
TraceAllAgent
class.
@Before("allMethodsAllClasses()")
public
void beforeTracedMethods(JoinPoint joinPoint) {
String
className =
joinPoint.getStaticPart()
.getSignature().getDeclaringTypeName();
.
. .
}
Conditional advice execution
Point cut method is usually empty, unless you use
if()
pointcut expression:
@Pointcut("call(*
*.processEvent(JComponent)) && args(eventSource) &&
if()")
public static boolean someCallWithIfTest(Widget w)
{
return eventSource instanceof
JButton;
}
Note that return value is now boolean and not void. Call the advice only when only when condition is satisfied, that is when processMedhod parameter is JButton and
only then.
Maven dependencies
<
dependency
>
<
groupId
>
aspectj
</
groupId
>
<
artifactId
>
aspectjweaver
</
artifactId
>
<
version
>
1.5.4
</
version
>
</
dependency
>
<
dependency
>
<
groupId
>
aspectj
</
groupId
>
<
artifactId
>
aspectjrt
</
artifactId
>
<
version
>
1.5.4
</
version
>
</
dependency
>
<
dependency
>
<
groupId
>
aspectj
</
groupId
>
<
artifactId
>
aspectjtools
</
artifactId
>
<
version
>
1.5.4
</
version
>
</
dependency
>
Much newer version of AspectJ is
available in the time of writing – AspectJ
1.7.1.
However in main Maven repository was 1.5.4 still the latest so I stuck with it. No issues.
However in main Maven repository was 1.5.4 still the latest so I stuck with it. No issues.
Interesting links
AspectJ homepage - http://www.eclipse.org/aspectj/
http://www.eclipse.org/aspectj/doc/released/progguide/index.html
- The AspectJ Programming Guide
http://www.eclipse.org/aspectj/doc/released/adk15notebook/
- The AspectJ 5 Development Kit Developer's Notebook
http://www.eclipse.org/aspectj/doc/next/devguide/ltw.html
- Load-Time Weaving chapter in Developers Guide. Also explains
Compile-time and Post-compile weaving.
AJDT or Eclipse plugin for AspectJ
http://www.eclipse.org/aspectj/doc/next/adk15notebook/annotations-pointcuts-and-advice.html
- Join Point Matching based on Annotations. Do NOT confuse this with
annotation based style. This chapter is about intercepting only
methods with certain annotation and similar rules.
http://www.eclipse.org/aspectj/doc/next/progguide/semantics-pointcuts.html – list of all (?) possible pointcut definitions with examples.
Note, everything is in code based style. But you should be now able
co convert them to annotation based style. See chapter above.
http://www.eclipse.org/aspectj/doc/released/faq.php#q:comparecallandexecution
What is the difference between call and execution join points?
Summary: Since AspectJ 1.1 you should use the execute() pointcut designator unless you have a good reason to use call().
What is the difference between call and execution join points?
Summary: Since AspectJ 1.1 you should use the execute() pointcut designator unless you have a good reason to use call().
http://www.eclipse.org/aspectj/doc/released/faq.php#q:codeversusannotationstyles
Should I use code- or annotation-style aspects?
Should I use code- or annotation-style aspects?
http://www.eclipse.org/aspectj/doc/next/progguide/starting-aspectj.html#inter-type-declarations
– another interesting feature of AspectJ. You can add methods, fields and even modify
hierarchy using these inter type declarations. However, it looks like
it can be used only with compile time weaving, not LTW.
Appendix – code to locate AspectJ jar on classpath
To detect full path to AspectJ agent library,
something suitable for tests, not tied to any file system layout, I
wrote this utility method:
public
static
String getAspectjWeaverJarFullPath() {
ClassLoader
loader = SampleMultithreadAppTest.
class
.getClassLoader();
String
aspectjTypicalClass =
"org/aspectj/weaver/ltw/LTWeaver.class"
;
String
aspectjUrl = loader.getResource(aspectjTypicalClass)
.toExternalForm();
return
aspectjUrl.substring(aspectjUrl.indexOf(
'/'
)
+ 1,
aspectjUrl.indexOf(
".jar!"
)
+ 4);
}
The method looks for a prominent AspectJ class,
containing pre-main method, the entry point of any Java Agent.
Classes can be seen as files in a directory, so ClassLoader is able
to find them by
getResource()
,
don't forget to use “/”instead “.” and add file suffix of
“.class”. Method toExternalForm
then return something
like:jar:file:/home/dev/maven_repo/org/aspectj/aspectjweaver/1.5.4/aspectjweaver-1.5.4.jar!/org/aspectj/weaver/ltw/LTWeaver.class
.
With some careful text stripping we can get path to AspectJ weaver
jar. AspectJ weaver jar has to be on the classpath, we can take it as
granted here, see the general requirements in the previous article.
This approach is better alternative to search
through classpath string. It can deal with non-standard AspectJ
names, like having version included in name or not, or non-standard
assembly, like bulk all-in-one JAR. Until
LTWeaver
class in package org.aspectj.weaver.ltw
,
it will work.
No comments:
Post a Comment