|
aop
[
jonas
]
13:22, Tuesday, 25 October 2005
Introducing HyperBeans – multi-dimensional POJOsIntroductionThis article is introducing HyperBeans, a proposal for a framework for Symmetric Aspect-Oriented Software Development in plain Java (i.e. no extensions to Java is being used). These ideas are based on the work I have done in AspectWerkz and in the JVM support for AOP in JRockit and are loosely based on the work on Classpects by Kevin Sullivan and Hridesh Rajan. If you don't care about the research and background behind the ideas presented in this article (and want to see some code right away), then you should skip the rest of this section. Aspect-Oriented Software Development (AOSD) in general, tries, among other things, to address the problem defined as the tyranny of dominant decomposition , in which the prominent concerns, usually the business logic, dominate the class design, especially the inheritance hierarchy (as observed in this article). Historically there has been (and still is) two different main philosophies in AOSD, the asymmetric philosophy and the symmetric philosophy. A detailed discussion about their semantic and philosophical differences is out of the scope for this article (read this article for a detailed discussion). Juri Memmert has written a good introductory article on the subject in which he defines the different philosophies like this: The asymmetric philosophy The leading implementation for asymmetric AOSD is AspectJ, while the most well-known symmetric implementation is Hyper/J (now part of the Concern Manipulation Environment (CME) project). Asymmetric AOSD has so far been the dominant way of implementing AOSD in Java, and in the enterprise space at large. There has been, and still is, a lot of debate in the research community around whether the symmetric or the asymmetric philosophy is the best way of implementing AOSD and many papers have been written on the subject (see the reference section at the end). When implementing the AspectWerkz AOP framework (which now has been merged with AspectJ), I have been involved in efforts trying to stretch the boundaries of asymmetric AOSD and even though I believe that the asymmetric approach is the preferable in many cases, it definitely has some shortcomings. For example, asymmetric AOSD addresses the problem of 'the tyranny of dominant decomposition' by allowing us to modularize all concerns, but the dominant concern, using aspects. Since the dominant concern needs to serve as "base", the decision deciding which concern should be seen as the dominant one still needs to be taken, and this is a decision that should not be taken lightly since it is something that is usually very hard to change. When taking a look at how a symmetric approach handles the above given problem, I find the symmetric solution very natural and appealing (at least conceptually). In which, if using Hyper/J's terminology, a system is seen as a multi-dimensional hyperspace, which is built up using different hyperslices (dimensions). A hyperslice is the abstraction of a concern, which can be built up by many components. This gives you the possibility of viewing the hyperspace (your system) differently in regards to different hyperslices (concerns); you have the possibility of looking at the system from the point of view (concern) that you currently want. I do not want to take any position in regards to if symmetric AOSD is a (or will be a) serious contender to asymmetric AOSD. I simply have not used the symmetric approach to solve real world problems enough yet, but I do believe that it is something worth exploring more. So, let's take a look at the proposal. HyperBeans – multi-dimensional POJOs
There is no the distinction between classes and aspects, e.g. no need for one concern to serve as "base", all there is is HyperBeans. HyperBeans are regular Plain Old Java Objects (POJOs), they are instantiated with Similarly, there is no the distinction between methods and advice, there are just regular methods, which can be invoked explicitly (like regular methods) or implicitly (when a join point is being executed - like a regular advice). Deployment and undeployment
HyperBeans are instantiated using the Deployment of a HyperBean means that its "blessed" methods (advice) are weaved in, while undeployment means that the woven code is removed.
You control deployment of a HyperBean by annotating (one or many of) its constructors with the
public class POJO {
@Deploy
public POJO() {
}
... // remaining methods omitted
}
Since there is no such thing as 'destructors' in Java, we are handling undeployment of HyperBeans by annotating a regular Java method (static or member) with the
public class POJO {
@Undeploy
public void close() {
// clean up - close resources etc.
}
... // remaining methods omitted
}
Instantiation models
You can control instantiation model (also called the deployment scope) of the HyperBean by adding a special argument to the constructor. This special argument defines the deployment scope for the HyperBean and needs to be annotated with the
For example, adding the argument Here are all the currently supported instantiation models:
Here are some examples:
public class POJO {
/** Singleton deployment */
@Deploy
public POJO() {
}
/** Per Type deployment */
@Deploy
public POJO(@Scope Class scope) {
}
/** Per Instance deployment */
@Deploy
public POJO(@Scope SomeType scope) {
}
/** Per Thread deployment */
@Deploy
public POJO(@Scope Thread scope) {
}
... // remaining methods omitted
}
The current semantics for the
Control flow management - no more cflow
There is no more any need for the cflow pointcut (as defined by AspectJ). Instead we suggest a simple programmatic model for control flow management of HyperBean deployment. I believe that the same functionality can be reached by a combination of the Per Thread instantiation model and the deployment/undeployment API. This approach has similarities with the work done in CaesarJ and its concept of a You have a HyperBean that can be deployed on a per-thread basis:
class POJO {
@Deploy
public POJO(@Scope Thread scope) {
}
@Undeploy
public void close() {
}
... // remaining methods omitted
}
Then you can use the following idiom to achieve fine grained control flow (cflow) management:
POJO hyperBean;
try {
hyperBean = new POJO(Thread.currentThread()); // deploys the HyperBean to the current control flow ONLY
... // do stuff - the HyperBean is woven into this control flow ONLY
} finally {
hyperBean.close(); // undeploy the HyperBean from the control flow
}
If you don't want to have this be tangled with your application logic, you can of course put the block in an advice, (and have its HyperBean be a singleton and instantiated somewhere else):
@Around(..)
public Object cflowAdvice(InvocationContext ctx) {
POJO hyperBean;
Object result;
try {
hyperBean = new POJO(Thread.currentThread());
result = ctx.proceed();
} finally {
hyperBean.close();
}
return result;
}
Cross-cutting methods - adviceSo how do we define these "blessed" methods? They are defined using Java 5 annotations, in a similar fashion to AspectWerkz's and AspectJ 5's annotation style of development, but mixed with the API defined by the JVM support for AOP in JRockit (as described in this article ). Let's take a look at an example:
public class POJO {
@Before("call(Foo.new(..))")
public void doSomething() {
... // do something before an instance of Foo is created
}
... // remaining methods omitted
}
This is a regular POJO with one "blessed" method that performs some action before an instance of
public class POJO {
@Before("call(@test.TraceMe * *.*(..))")
public static void traceBefore(@CalleeMethod Method callee) {
System.out.println("--> " + callee.toString());
}
@After("call(@test.TraceMe * *.*(..))")
public static void traceAfter(@CalleeMethod Method callee) {
System.out.println("<-- " + callee.toString());
}
... // remaining methods omitted
}
This is a regular POJO with two different "blessed" methods (that are tracing
invocations to all methods that are annotated with the Here is a list of the current set of defined annotations and their meaning:
These annotated arguments (except caller and callee method) also works as 'filters', the same is true for all unannotated arguments which are treated as the regular arguments to the method (or the field value about to be set etc.). The methods can be either member or static (dependent on if you want to keep state in the instance or not).
Since some people might be curious how "around advice" (i.e. 'interception') is handled, below is an example of how to implement the same functionality as in the class above using an "around advice". Here we introduce the
public class POJO {
@Around("call(@test.TraceMe * *.*(..))")
public Object trace(InvocationContext ctx,
@CalleeMethod Method callee) {
System.out.println("--> " + callee.toString());
Object result = ctx.proceed();
System.out.println("<-- " + callee.toString());
return result;
}
... // remaining methods omitted
}
ImplementationI have prototyped HyperBeans using the JVM support for AOP in JRockit. The implementation was actually very simple and shows the power of the JRockit API (the JRockit prototype is available now for those who wants to try it out). I am planning on writing another article in which I go through (and release) the actual implementation. Stay tuned.
[
jonas
]
16:43, Wednesday, 31 August 2005
Japan Tour My Japan tour is starting to come to an end. During the past week I have been traveling in Japan, done two general sessions at BEA Tech Day 2005 conferences (Tokyo and Osaka), plus a press conference and a bunch of BEA internal training sessions. I had never been to Japan before, but I am very interested in their culture and I love Japanese food, so this trip has in many ways been a very interesting and fun experience. I had some fears that my visit would turn out similar to the movie 'Lost In Translation' by Bill Murray (for those that have seen this movie), but my fears were unfounded. Most people spoke good english and I only met very generous people with a lot of heart. Excitement around AOP There is a lot of excitement and interest around AOP in Japan, both among developers, management and press. They are especially excited about AspectWerkz (it is actually more popular than AspectJ) and JRockit support for AOP. It was fun to learn that they had translated every single article I have written, to Japanese. On the other hand, the problem having to translate almost every article and book is one of the biggest hurdles on the way to mass adoption of AOP. Press conference The press conference I did was an interesting experience, it was my first real press conference, with interviewers lined up, pounding me with questions. It was a lot of fun. The topic for the interview was JRockit and its new AOP support which they seemed very impressed about. They have already published, two articles based on the press conference: BEA Tech Day 2005 in Tokyo The general session I did had around 350 attendees and was simultaneously translated. Things worked out pretty well. People seem to like the talk and came up with a bunch of really good questions at the end. What was even more fun was that there were actually other speakers that talked about AspectWerkz/AspectJ in different contexts. One guy for example, talked about how to implement the transaction and dependency injection parts of the EJB 3 specification using AspectWerkz. In general, one of the main themes of the conference was AOP. Afterwards, during the conference party, I was treated almost like a celebrity, with "fans" coming up and wanted to shake hands and have a picture taken with the mysterious AOP guru from the north pole (Sweden). :-) Seasar framework - a Japanese Spring killer? During lunch at the conference I had the pleasure of having interesting discussion with the founder of the dependency injection and component framework Seasar. For those that have never heard about Seasar, Seasar is a project very similar to Spring, which is more popular than Spring here in Japan. It uses plain bytecode manipulation to do the AOP part (and not proxies), and is based on the AOP Alliance interfaces. One cool thing that I found out about the project is that they are not only using but are very excited about Alex's and my project backport175 (so much that they actually asked to contribute back some code). BEA Tech Day 2005 in Osaka - Kyoto sightseeing Today I am off for Osaka for my last talks at the BEA Tech Day 2005 in Osaka tomorrow. The trip will conclude with one day off, which I will spend sightseeing in Kyoto. Kyoto is the historical and cultural center in Japan, with many buildings and temples being more than 1000 years old (compared to Tokyo which is only a couple of hundred years old). So that is going to be interesting.
[
jonas
]
21:18, Monday, 8 August 2005
The second part of our article series about JRockit JVM support for AOP is now published. This article describes in more detail on how the API is used, showing some code samples and ends with a discussion in which we try to explain how we address the questions and issues (around the shortcomings of bytecode manipulation) raised in part one in the series. The prototype will be downloadable soon, stay tuned.
[
jonas
]
12:07, Monday, 18 July 2005
As I mentioned in my previous blog entry, the synchronized
block is currently not a supported join point in AspectJ 5 (or in any other AOP framework):
Currently you can for example pick out a call to a method that is declared as being synchronized and you can pick out calls to Thread:: notify()/notifyAll()/wait(). Meaning that being able to pick out synchronized blocks are the only missing piece left in order to completely control thread management and locking in Java. The actual bytecode modifications needed to make this work would be fairly simple, but capturing the correct semantics in a good language design would probably be a lot trickier. Well, I'm not a language designer, but I think the problem is interesting so I will spend some time discussing it anyway. In bytecode, a synchronized block is represented as a MONITOR ENTRY and a MONITOR EXIT bytecode instruction pair (however these are not required to be paired). The first natural approach would to let these two bytecode instructions be join points and treat them similar to field access and modification (PUTFIELD and GETFIELD bytecode instructions), meaning simply pick out (and intercept) this single bytecode instruction. Just to clarify what I mean, here is an example of how the syntax for the above given semantics could look in the AspectJ pointcut expression language: lock(Type t) && withincode(* Foo.bar(..)) && args(t) unlock(Type t) && withincode(* Foo.bar(..)) && args(t) Let us take a look at a synchronized block and how it would be affected: synchronized(obj) { // body } In bytecode to this is equivalent to (pseudo code): MONITOR ENTRY // lock on obj // body MONITOR EXIT If we now add around advices to these join points then we could for example get (pseude code): try { // a call to the around advice, which calls the lock manager aroundAdvice1(obj) --> myLockManager.acquire(obj); // body } finally { aroundAdvice2(obj) --> myLockManager.release(obj); } This approach would give you the possibility to completely control how locking is done in Java (including the possibility of enhancing or completely screw up the Java Memory Model (JMM)). On the other hand it does not allow you to pick out the actual code block that is synchronized (is this something that we want?) . Therefore this approach is perhaps not intuitive, since in Java source code, what we see is not lock acquisition and release but a code block that is guaranteed to be synchronized. So now let's try to approach this problem from the perspective of source code. Since AspectJ (and AspectWerkz) already has limited support for the synchronized keyword by allowing calls to methods declared as being synchronized to be matched, let us take a look at the semantics for this join point. Here's a simple method that is defined as being synchronized: public synchronized void doStuff() { // body } What this actually means is: public void doStuff() { synchronized(this) { // body } } The options we have of picking up this synchronized code block (wrapped up in the doStuff() method) is by using a execution(synchronized void *.doStuff())or call(synchronized void *.doStuff())pointcut. Using the execution pointcut, the above method body would be transformed to (pseudo code): synchronized(this) { // the advice has option of invoking the original body myAroundAdvice(this) } I.e. only synchronized body is matched and intercepted. If we are using the call pointcut, the same code snippet would be transformed to (pseudo code): ... // the advice has the option of invoking the original synchronized block myAroundAdvice(this) ... I.e. the whole synchronized block, including the locking is matched (and intercepted). (This is conceptionally true, in regards to the locking, which is easy to see if you think of the doStuff() method as being inlined.)
I will not go into much detail about how these semantic differences should be expressed in the pointcut language here (this post is too long already). But for example, the last discussion would require the possibility of making a distinction between picking out a code block // pick out synchronized block including the locking block-inclusive(synchronized(Type t)) && withincode(* Foo.bar(..)) && args(t) // pick out only the synchronized block's body, not the locking block-exclusive(synchronized(Type t)) && withincode(* Foo.bar(..)) && args(t) (These "block" pointcut descriptors can of course be used in any kind of block, loops, conditional statements etc., if/whenever they are supported in AspectJ.) To sum up, the questions are: Do we want the power of intercepting the whole locking mechanism (but not the synchronized body), or is it better to follow the semantics we have for a synchronized method? Which approach addresses the use cases we want? Is the most intuitive? Is more orthogonal? Thoughts? Comments? Ideas?
[
jonas
]
15:34, Tuesday, 7 June 2005
Terracotta just recently launched a product (DSO) for clustering POJOs in a completely transparent way. What I find interesting in this product is not mainly in the clustering and caching, but how they make use of AOP and loadtime weaving to make it completely transparent. This sounds a lot like techniques that we have been working on in AspectWerkz last years, and I was not too surprised, although very happy, to learn that they are actually using AspectWerkz. It is really great to see some of the ideas that Alex and I have been working on being used in new and interesting ways and in real-world applications. They seem to use techniques that are fairly similar to the Unit of Work aspect library that I wrote for the AWare aspect library. Meaning: record field changes to object graphs within a transaction which can be committed/rolled back./etc. add specific methods that are defined declaratively. However they have extended to this idea by adding semantics currently not available in AOP. For example being able to pick out synchronized blocks. This is a great idea, and when you think of it, it is in a way a hole in the current AOP implementations. Currently you can for example pick out a call to a method that is declared as being synchronized and you can pick out calls to Thread:: notify()/notifyAll()/wait(). Meaning that being able to pick out synchronized blocks are the only missing piece left in order to completely control thread management and locking in Java. The actual bytecode modifications needed to make this work would be fairly simple, but capturing the correct semantics in a good language design would probably be a lot trickier. All and all a very interesting product that shows the beauty of AOP and loadtime weaving in action, go and check it out. /Jonas
[
jonas
]
20:02, Sunday, 29 May 2005
If you're interested in knowing more about what the future holds for AOP, then you should come to the technical session TS-7659 (titled "Runtime Aspects With JVM Support") on Tuesday, June 28 at JavaOne 2005. This will be the first time ever to show an enterprise JVM - BEA JRockit - with native AOP support. Alex Vasseur and myself have been pushing for this idea since the early days of AspectWerkz when we joined the JRockit group, and it's finally taking shape, with now support for AspectJ 5, the de-facto standard for AOP in Java. Credit should also go to Joakim Dahlstedt, the CTO of JRockit, who has been playing a leading role in the design and implementation. We will talk about the current problems with bytecode based weaving (multiple agents, double bookkeeping, performance etc.) and then discuss how these problems can be solved through native JVM support. We will show a prototype of our implementation, go through the programming model and run a live demo. Here is the abstract: "Aspect Oriented Programming (AOP) is growing in popularity. Adding aspects at runtime, dynamic weaving, can be a very powerful technique for diagnostics, profiling, or debugging of a running system. The concept of adding aspects at runtime (dynamic weaving) is looked upon with skepticism by some. It's also easy for multiple instrumenting agents to cause havoc for each other. We have implemented prototype changes to our Java™ Virtual Machine (JVM™ software), BEA Weblogic JRockit, to support dynamic weaving in the JVM software in a controlled fashion. We also have modified AspectJ 5 to try out this functionality. We believe our changes to the JVM software to support dynamic weaving lessens the skepticism about runtime aspects and allows for multiple instrumenting agents to coexist. Don't miss it, see you there.
[
jonas
]
10:17, Friday, 20 May 2005
I just got back from the Nordic Software Developer Summit (Nordev) 2005. Strange enough, this is the first good developer conference that we have had in Sweden. Altogether it was a really good event with two major tracks, one Java and one .Net. The Java track had interesting talks on topics like: AOP :-), agile development, hibernate, spring, manageability of the JRockit JVM etc. (e.g. the usual suspects). I was glad to see that AOP got a lot of focus with talks from myself and Rickard Oberg and a hands-on workshop (on AspectJ). Both sessions were packed, and people seemed enthusiastic about it. Of all things you can be nervous about, I was nervous about speaking in Swedish (my native language). I had never spoken about AOP in Swedish so it was interesting and a good exercise :-). Everything went pretty well except that eclipse died on me when I was starting up the demo (3.1 M6). (The demo was about how to write a unit of work to achieve transparent persistence/replication/transaction management, perhaps something for an upcoming blog post...). I enjoyed Rickard's talk. He based the talk on examples from the CMS application and he has built, and it was interesting to see both simple and advanced usage of AOP in the real world application. He's using a pretty extreme approach to AOP in which every single object is built up a using intertype declarations (introductions/mixins). I do not think that this model fits every project, and it for sure has drawbacks, but in their CMS application it has given them extremely high reuse and development speed. He showed examples of client aspects, how objects can render themselves differently based on which intertype declarations it has. For example, if an object in their GUI (a page, a site, a portlet etc.) has the intertype declaration ACL applied to it then it will give you the possibility to open up a window to manage security for this object. This object can also be given the Tree intertype declaration, which will allow you to browse the object in a tree structure etc. He also showed examples on how they do client synchronization and cluster wide replication, using the same aspect (which simply records the events triggered and then plays it back). Another interesting aspect that they have is what he calls partial object versioning, in which intertype declarations can be versioned and different versions can be used (in the same object), depending on how system is configured. Rickard gave an example of a customer that came in with a new functional requirements very late in the release cycle, requirements that required redesign of some parts of the system, but that he managed to solve in a simple and generic way by applying an aspect. Then he talked about the need for tools and that most problems that people are complaining about when it comes to AOP are actually not related to AOP, but to the lack of good tools. He showed one interesting tool that they are using on a daily basis, a tool for doing a diff of the system. This diff showed you which advice and or intertype declarations had been removed or added since the last time the system's state was recorded. For example, after a regular refactoring, the diff should be zero. This is something that we should add to AJDT. All and all a good conference, you should try to get there next year.
[
jonas
]
21:28, Tuesday, 15 March 2005
AOSD 2005 has just started. I am excited, and have high expectations since last years conference was a real hit, and this year we have a separate industry track with many interesting talks coming up, f.e. Grady Booch is doing a keynote. I will be giving a talk on AspectWerkz 2 and the road to AspectJ 5 at the AOSD 2005 conference hosted at the Intercontinental hotel in Chicago. If you are in the area, please drop in and say hi. If you are interested you can read the abstract etc. here For those who can't make it, I will make the slides available online after the conference. Hope to see you there...
[
jonas
]
17:10, Thursday, 6 January 2005
One of the new features in the AspectWerkz 2 architecture is that it comes with a full-blown interception framework that allows per instance programmatic deployment with most of the AOP semantics preserved. You can make use of this using both the regular load-time weaving or the AW Proxy (that I blogged about here)
In short you will get:
POJO pojo = new POJO();
// adds tracing to all methods in the 'pojo' instance
((Advisable) pojo).aw$addAdvice(
"* *.*(..)",
new BeforeAdvice() {
public Object invoke(JoinPoint jp) {
System.out.println("Entering: " + jp.getSignature().toString());
}
}
);
The Advisable interface
From a users perspective pretty much all you need to know about is in the
The
aw$
is just to minimize method clashes since these methods are added to your classes on-the-fly.
The different Advice interfacesThe intercept framework supports all main types of advice defined in AOP today:
JoinPoint
instance as a parameter. This class contains f.e. contextual information bout the join point (member) we are executing before/after/around. Such as caller and callee instances and types, argument values and types etc. You can also see that some of the advice takes an optional parameter which provides direct access to the return value or the exception instance.
Preparing your application
To make this work you finally need to tell AspectWerkz which classes you want to make "advisable" and to which extent. This is done in the
Example:
<aspectwerkz>
<system id="intercept-sample">
<advisable expression="within(my.application.domain.*)" pointcut-type="call|set|get"/>
</system>
</aspectwerkz>
Bringing it all together
So now we have talked about the
In this example we are taking a regular POJO and we are adding an advice that will be applied to all methods that are annotated with the annotation
...
POJO pojo = new POJO();
((Advisable) pojo).aw$addAdvice(
"@OneWay * *.*(..)",
new AroundAdvice() {
private Executor m_threadPool = Executors.newCachedThreadPool();
public Object invoke(JoinPoint jp) throws Throwable {
m_threadPool.execute(
new Runnable() {
public void run() {
try {
// proceed with the invocation in a new thread
jp.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
);
return null;
}
}
);
...
The META-INF/aop.xml
file looks like this:
<aspectwerkz>
<system id="intercept-sample">
<advisable expression="within(sample.intercept.POJO)" pointcut-type="call"/>
</system>
</aspectwerkz>
Resources
I have not written any specific sample application for this article but if you want you can look at and run the tests in the AspectWerkz distribution. You can download the distribution here. The tests are in
[
jonas
]
04:12, Wednesday, 15 December 2004
One of the new features in the AspectWerkz 2 architecture is the ability to deploy and undeploy aspects at runtime, e.g. to do "hot" deployment and undeployment. The implementation is based on HotSwap class redefinition and handles 'change sets' which ensures that the changes to each single join point is atomic. What this means in practice is that if you for example are deploying an aspect which has one before and one after advice, both advising the same join point (method/field etc.) then either both of them will be added or none.
The API exposed to the user is very simple and straight forward to use. Everything is handled by the
DeploymentHandle deploy(Class aspect)
DeploymentHandle deploy(Class aspect, ClassLoader deployLoader)
DeploymentHandle deploy(Class aspect, DeploymentScope scope)
DeploymentHandle deploy(Class aspect, DeploymentScope scope, ClassLoader deployLoader)
DeploymentHandle deploy(Class aspect, String xmlDef)
DeploymentHandle deploy(Class aspect, String xmlDef, ClassLoader deployLoader)
DeploymentHandle deploy(Class aspect, String xmlDef, DeploymentScope scope)
DeploymentHandle deploy(Class aspect, String xmlDef, DeploymentScope scope, ClassLoader deployLoader)
void undeploy(Class aspect)
void undeploy(Class aspect, ClassLoader loader)
void undeploy(DeploymentHandle deploymentHandle)
As you can see you can for example choose to deploy an annotation defined aspect, e.g. a regular Java5 class with AspectWerkz defined annotations (or a regular Java 1.3/1.4 class with AspectWerkz defined JavaDoc annotations, compiled with AspectWerkz's JavaDoc annotation compiler):
DeploymentHandle
(that is returned from each of these methods) here.
You also deploy a class without any annotation definition and pass in the definition in XML format. Here you pass in a string containing the Use-case: Implementing a JMX monitoring aspectNow let's take a look at a concrete example on how to hot deploy an aspect that can do some monitoring for us, report that to an JMX MBean and then undeploy it when the monitoring is done. Writing the aspectSo first, here is the (main parts of the) JMX monitoring aspect:
@Aspect
public class ResponseTimeAspect {
... // methods for registering the MBean lazily, member fields etc.
// the "invocationsToMonitor" pointcut will be defined at deployment time
// in the aop.xml file
@Around("invocationsToMonitor")
public Object monitor(StaticJoinPoint jp) throws Throwable {
Signature signature = jp.getSignature();
long tsStart = System.currentTimeMillis();
Object result = null;
try {
result = jp.proceed();
} finally {
// note: this code is using a JMX helper method and
// we will have one MBean per jointpoint signature (i.e. method, field, etc.)
long tsElapsed = System.currentTimeMillis() - tsStart;
ObjectInstance mbeanI = registerMBean(signature);
if (mbeanI != null) {
m_mbeanServer.invoke(
mbeanI.getObjectName(),
"update",
new Object[]{new Long(tsElapsed)},
new String[]{long.class.getName()}
);
}
}
return result;
}
public static void enableMonitoring(String pointcut) { ... }
public static void disableMonitoring() { ... }
}
As you can see, this aspect is defined using Java5 annotations, but if you are using Java 1.3/1.4 you can define the annnotations using JavaDoc (just put the annotation exactly as it is in the JavaDoc for the method/class) and run AnnotationC
on the class. Then the rest in this article should stay the same. You can read more about the AnnotationC
compiler here.
Hot deploy and undeploy the aspectAs you can see we have added two static methods to the aspect, these will be used to enable and disable the response time aspect. E.g. deploy it and undeploy it.
First we have the
public static void enableMonitoring(String pointcut) {
String xmlDef = "<aspect><pointcut name='invocationsToMonitor' expression='" + pointcut + "'/></aspect>";
Deployer.deploy(ResponseTimeAspect.class, xmlDef);
}
Second we have the
public static void disableMonitoring() {
Deployer.undeploy(ResponseTimeAspect.class);
}
Use the aspect to monitor JDBC SQL statementsThis means that in the user code, all we need to do to enable and disabling this aspect is to invoke these two methods. Here we will monitor the executions of all JDBC statements:
public static void trackResponseTimeOfSqlQueries() {
ResponseTimeAspect.enableMonitoring("call(* java.sql.Statement+.execute*(..))");
... // wait a while to do a recording
ResponseTimeAspect.disableMonitoring();
}
What this pointcut expression (
Note: we could in this specific use-case benefit from retrieving and storing the parameter value to the So now after doing some monitoring you should be able to easily see the data in any JMX console. For example hook in JConsole which you can read more about in this article. Define a deployment scopeFinally, to get this to work in the general case we need to define a deployment scope which defines the set potential join points that we might want to monitor at runtime. This construct gives you (as a application developer or vendor) control over which join points are exposed to the hot deployment API i.e. helps to prevent usage of the hot deployment facilities in specific areas of the application.
This can be done either in the
<aspectwerkz>
<system id="monitoring">
<deployment-scope name="response_time" expression="call(* sample.deployment..*.*(..))"/>
</system>
</aspectwerkz>
Here we have defined a deployment scope that picks out all method calls in our sample application, which means that we can safely deploy our In the code above we have an implicit contract that says that we can not define the aspect to be deployed outside a deployment scope. If we do not define a pointcut that is wider than this it is all fine. But we can now use this deployment scope to ensure that we only deploy the aspect at valid points. To do that we need to retrieve a handle to the scope like this (can be done at any point):
DeploymentScope scope = SystemDefinition.getDefinitionFor(loader, systemId).getDeploymentScope("response_time");
Now we can use the
Deployer.deploy(ResponseTimeAspect.class, xmlDef, scope);
Notes on the impact of the deployment scope preparation
The preparation made by the deployment scope construct means in practice that we are simply adding a level of indirection by adding a call to a When we do undeploy of an aspect, if this aspect is the last one that affects the join point, then the class' bytecode will be reverted to the same state it had before any aspect was deployed. ResourcesMore info about the JMX ResponseTimeAspect
The code for the monitoring aspect is based on the implementation of the You can also check out the complete AWare project which has some tests for the JMX module. Info about how to check out the sources can be found here. More info about the Deployer Module
I have not written any specific sample application for this article but if you want you can look at and run the tests for the deployer module in the AspectWerkz distribution. You can download the distribution here. The tests are in
The
[
jonas
]
19:50, Monday, 13 December 2004
The ideaAfter implementing the AW Proxy extension to AspectWerkz I figured, why not hook into the most widely used proxy implementation out there: cglib and let AspectWerkz weave in the aspects that are around just before the proxy is returned to the user. The solutionSo, this is all that this cglib extension does: asks AspectWerkz if it has anything to say about the class that has just been proxied. If so, then let the AspectWerkz weaver do its job, e.g. weave in the aspects that are currently deployed (on the classpath), and when returns the proxy to the user. If no AspectWerkz aspects are found that has pointcuts that matches the class being proxied then nothing happens. All that was needed to make this work was to add 30 lines of code to one single cglib class. How do I use it?
This means that all you need to do to make any cglib based applications, and there are many: Geronimo, dynaop, Spring AOP, Hibernate etc., become "aspectwerkz-aware" is to replace one single class in the Or.
If you can't or don't want to patch the What is the impact on my existing code?If no AspectWerkz aspects are found that has pointcuts that matches the class being proxied then nothing happens. And if AspectWerkz is not available then the whole process is skipped. So basically, there is nothing to loose, it is pay as you go (or should I rather say: gain as you go ;-) ). How do I get it?The single file you need can be found in the AspectWerkz RC2 distribution, which you can find here.
The cglib extension is in the
In the Enjoy.
[
jonas
]
05:31, Wednesday, 8 December 2004
SummaryProxies are an important piece in the J2EE puzzle. Since it offers a non-intrusive an more transparent way of weaving in advice/interceptors. However, non of the current proxy implementations utilizes all the rich semantics of AOP (as defined by AspectJ), the expressiveness of a real pointcut pattern language and has the speed of statically compiled code. AW Proxy is here to try to narrow this gap. It makes use of the rich semantics for AOP in AspectWerkz and is very high-performant due to the use of static compilation (utilizing the AspectWerkz weaver). All wrapped up a very simple and intuitive API. The need for proxiesThe two arguments against load-time weaving that we hear the most are:
Adding the possibility of using AspectWerkz together with proxies is something that Alex and I have been talking about for a long time but never implemented due to lack of time. Well, this weekend I took the time and it was actually more simple than I thought. After a couple of hours coding (taking the cglib route with its "class proxy", e.g creating a new class on-the-fly that extends the target class and which methods and constructors delegates to the base class' methods, but with the difference that they don't wrap the arguments but pass them on as they are, which gives a lot better performance), I had a working solution. Introducing AW ProxyThe benefit with using the AspectWerkz Proxies compared to the regular load time weaving is that there are no VM options. You simply create your proxy and before it is returned to you it is weaved with the aspects that happens to be available on the classpath at that time. The API is pretty straight forward. All you need is in the
org.codehaus.aspectwerkz.proxy.Proxy
class which has the following API:
// Returns a new proxy for the class specified
public static Object newInstance(Class clazz);
// Returns a new proxy for the class specified, instantiates it by invoking the constructor
// with the argument list specified
public static Object newInstance(Class clazz, Class[] argumentTypes, Object[] argumentValues);
// Same as above, but with optional parameters for caching and making the proxy advisable
public static Object newInstance(Class clazz, boolean useCache, boolean makeAdvisable);
// Same as above, but with optional parameters for caching and making the proxy advisable
public static Object newInstance(Class clazz, Class[] argumentTypes, Object[] argumentValues,
boolean useCache, boolean makeAdvisable);
How to use the API?
Here is a little example on how to use the
// creates and instantiates a new proxy for the class Target
Target target = (Target) Proxy.newInstance(Target.class, false);
That's it!
This Utilizing programmatic runtime deploymentAs I said before, when you create your proxy it will get automatically weaved with all the matching aspects that are found (on the classpath). This is most of the time what you want and need, but there might be cases when you want to add a specific feature, at runtime, to a specfific instance only. In these cases you need programmatic runtime per instance deployment. One of the new features in the AspectWerkz 2 architecture is that it comes with a full-blown interception framework that allows per instance programmatic deployment with most of the AOP semantics preserved.
In short you will get:
POJO pojo = new POJO();
// adds tracing to all methods in the 'pojo' instance
((Advisable) pojo).aw$addAdvice(
"* *.*(..)",
new BeforeAdvice() {
public Object invoke(JoinPoint jp) {
System.out.println("Entering: " + jp.getSignature().toString());
}
}
);
The advice "interceptors" that are supported are:
Now we can combine use this feature together with the AW Proxies. All proxies that are created implements the Example
In this example we create and instantiate a new proxy for the class
Advisable target = (Advisable) Proxy.newInstance(Target.class, true, true);
target.aw$addAdvice(
"String *.*(..)",
new AfterReturningAdvice() {
public void invoke(JoinPoint jp, Object returnValue) {
// do some stuff
}
}
);
BenefitsPlain proxies with rich AOP semantics
The benefits are, besides a less intrusive and more transparent approach, that you can utilize the rich semantics for AOP (well, not all, see below for limitations) that are supported AspectWerkz. Such as, a rich pointcut expression language, before/after/around advice, deployment modules defined by the Very high-performantYou will also get the full performance of the AspectWerkz 2 architecture. If you are interested details of the benchmark we made (and/or run it yourself) then you can read this paper. But in short AW Proxy is roughly:
Limitations
Since it is a proxy approach it only supports Resources
This new feature will be available in AspectWerkz 2.0 RC2 that will be available soon. Until then you can check out the sources from the CVS and build it yourself (by invoking
There are some samples in the Enjoy.
[
jonas
]
13:36, Monday, 6 December 2004
The AspectWerkz 2 architecture has been designed to be an Extensible Aspect Container, which can deploy and run arbitrary aspects. You can read more about the details in this article. In this article I will show you how you can make use of this container to run Spring AOP aspects more performant plus utilize the annotation-driven AOP in AspectWerkz along with its more expressive pointcut pattern language. In this article I am using Spring as an example but everything covered here applies to all frameworks that implements the AOP Alliance interfaces (e.g. dynaop, JoyAop, JAC etc.). Write a regular Spring adviceFirst we write a regular spring advice that implements authentication:
public class AuthenticationAdvice implements MethodBeforeAdvice {
public void before(Method m, Object[] args, Object target) throws Throwable {
// try to authenticate the user
// if not authenticated throw a SecurityException
}
}
Define the advice using Java 5 annotations
In this example we will not define this advice using the slightly verbose Spring config file. But make use of Java 5 annotations. In AspectWerkz you have a set of predefined annotations that we can use, f.e. one for each advice type. The advice we have implemented here is a before advice so we will use the
public class AuthenticationAdvice implements MethodBeforeAdvice {
@Before("authenticationPoints")
public void before(Method m, Object[] args, Object target) {
// try to authenticate the user
// if not authenticated throw a SecurityException
}
}
Here we bind the advice to the pointcut named "authenticationPoints"
, this pointcut will pick out all the points where we want authentication to take place. However we do not define this pointcut yet. Since we want to make this aspect reusable, then it is better to just compile it, put it in a jar and then at deployment time resolve this definition by defining the pointcut in the external META-INF/aop.xml
file.
We can of course choose to not define the pointcut in an external XML file but directly in the
@Before("call(@RestrictedOperation * *.*(..))")
public void before(Method m, Object[] args, Object target) {
...
}
if we think that that is beneficial. (Then the META-INF/aop.xml
only have to define the aspect class name, see below for details).
Define the pointcut in the external aop.xml file
Now all we need to do put this advice to work is to write the little
<aspectwerkz>
<system id="spring-extension-sample">
<aspect class="my.application.aspects.AuthenticationAdvice">
<pointcut name="authenticationPoints" expression="call(@RestrictedOperation * *.*(..))" />
</aspect>
</system>
</aspectwerkz>
Here we defined the pointcut to pick out all method calls to a method that is marked with the annotation @RestrictedOperation
.
Note that we are using a call pointcut here, which means that this advice will execute on the client side and not the server (something that is not possible with regular spring aop which only supports execution pointcuts). This can be beneficial in many situations, it can f.e. can save us a remove call from the client to the server, or take some load off the server if the client is executing in a separate VM, etc. Start up the applicationThe last thing we need to do is to add two VM options:
aspectwerkz-core-RC2.jar
, aspectwerkz-RC2.jar
, aw-ext-spring-0.1.jar
and aw-ext-aopalliance-0.1.jar
plus the regular AspectWerkz dependency jars on the classpath. (You find the aspectwerkz jars in the aspectwerkz distribution and the aw-ext-*.jar jars you need to build yourself (see Resources for details).
The you can start up the application as usual using
We have been thinking of providing a way of defining the spring aspect model on the application level (per What about my Spring bean config file, dependency injection etc?Good news is that you can still use your regular Spring bean config file and let Spring do its job, with dependency injection, bean configurations etc. AspectWerkz has a pluggable factory mechanism for the aspect instantiation and life-cycle management. We have written a factory for the Spring framework that allows you to use Spring to configure your aspects/advice just as usual. Read more about that here. Much better performanceApart from allowing defining your aspects using Java5 annotations and using the semantics of the AspectWerkz pointcut language and weaver, you will also get much better performance (ranging between 1300 to 50 percent). I won't go into detail on that here but you can read more about it in this article. DrawbacksEverything has tradoffs and there are of course some drawbacks in using the AspectWerkz Extensible Aspect Container as the runtime environment for your Spring aspects/advice:
Resources
I have not written any specific sample application for this article but if you want you can look at and run the tests in the AspectWerkz distribution. You can download the distribution here. The tests are in
The
[
jonas
]
08:28, Tuesday, 2 November 2004
I gave an interview for the spanish Java community site javaHispano.org.
Here is the
english version.
[
jonas
]
20:01, Tuesday, 31 August 2004
The Spring Framework is a very powerful library for J2EE development. It comes with an AOP implementation (based on proxies) that is in many cases sufficient in terms of what you need to do. However, there are many situations where you need a more full-blown AOP framework (such as AspectWerkz) to do the job.
On the other hand AspectWerkz (even though it has a decent API for configuration and management) could sometimes benefit from more finegrained and expressive configuration and life-cycle management, which is one thing that Spring does very well.
In short, it is sometimes beneficial to use these two frameworks together and I will now show you a first step on how you can make that happen.
AspectWerkz has a very open architecture in regards to
instantiation, configuration and management of the aspects. Here I will show you how you can make use of this to
take control over your aspects using Spring. (The concepts are the same for PicoContainer
, HiveMind or a home-grown IoC implementation.)
In AspectWerkz instantiation, management and configuration of aspects is handled by an "aspect
container" and to make it easier for users to provide their own custom implementation
it provides the abstract
org.codehaus.aspectwerkz.aspect.AbstractAspectContainer
class which handles all the nitty-gritty details.
All we have to do is to extend the
org.codehaus.aspectwerkz.aspect.AbstractAspectContainer
class and implement the abstract Object createAspect()
method.
So let us do that. Here is the implementation of our SpringAspectContainer
:
public class SpringAspectContainer extends AbstractAspectContainer {
public static final String SPRING_ASPECT_CONTAINER_CONFIG = "spring-bean-config.xml";
/**
* The Spring bean factory.
*/
private XmlBeanFactory m_factory = null;
/**
* Creates a new aspect container strategy that uses the Spring framework to manage aspect instantiation and
* configuaration.
*
* @param crossCuttingInfo the cross-cutting info
*/
public SpringAspectContainer(final CrossCuttingInfo crossCuttingInfo) {
super(crossCuttingInfo);
}
/**
* Creates a new aspect instance.
*
* @return the new aspect instance
*/
protected Object createAspect() {
if (m_factory == null) {
InputStream is = null;
try {
is = ClassLoader.getSystemResourceAsStream(SPRING_ASPECT_CONTAINER_CONFIG);
m_factory = new XmlBeanFactory(is);
} finally {
try {
is.close();
} catch (Throwable e) {
throw new WrappedRuntimeException(e);
}
}
}
// here we are letting Spring instantiate the aspect based on its name
// (the m_infoPrototype field is the CrossCuttingInfo instance passed to the base class)
return m_factory.getBean(m_infoPrototype.getAspectDefinition().getName());
}
}
This is all that is needed implementation wise. Now we only have to define which
aspects should be managed by our new container and configure the aspect in the
Spring bean config file.
To tell the AspectWerkz system that we want to deploy a specific aspect in our
custom aspect container we have to specify that in the regular
aop.xml
file like this:
<aspect class="some.package.MyAspect" container="some.other.package.SpringAspectContainer">
...
</aspect>
For details on the aop.xml
file (what it is, how it is used etc.) see the online documentation.
To configure the aspect we just configure it like any other Spring bean class:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="some.package.MyAspect"
class="some.package.MyAspect"
singleton="false"
init-method="intialize">
<property name="someProperty">
...
</property>
...
</bean>
...
</beans>
For details on how to define your bean classes see the Spring documentation. But
here are some explainations:
<bean id="org.codehaus.aware.security.RoleBasedAccessProtocol"
class="org.codehaus.aware.security.RoleBasedAccessProtocol"
singleton="false"
init-method="intialize">
<property name="type">
<value>JAAS</value>
</property>
<property name="roles">
<list>
<value>admin</value>
<value>jboner</value>
</list>
</property>
<property name="permissions">
<list>
<bean class="org.codehaus.aware.security.Permission">
<property name="role">
<value>jboner</value>
</property>
<property name="className">
<value>org.codehaus.aware.security.SecurityHandlingTest</value>
</property>
<property name="methodName">
<value>authorizeMe1</value>
</property>
</bean>
<bean class="org.codehaus.aware.security.Permission">
<property name="role">
<value>jboner</value>
</property>
<property name="className">
<value>org.codehaus.aware.security.SecurityHandlingTest</value>
</property>
<property name="methodName">
<value>authorizeMe2</value>
</property>
</bean>
</list>
</property>
</bean>
You can find the code for the SpringAspectContainer
along with many other reusable aspects in the AWare library.
Which is a community-driven OSS library for reusable aspects for AspectWerkz.
[
jonas
]
10:40, Friday, 11 June 2004
Yesterday evening I put together a series of two introductory tutorials on AspectWerkz (a third is on its way).
Tutorial one: Hello World.
Tutorial two: Hijacking Hello World
I hope that these will help you to get started with AspectWerkz.
Enjoy.
[
jonas
]
13:40, Monday, 5 April 2004
Just got back from the AOSD 2004 conference. Great experience. Had fun, attended many great talks, met a lot of interesting people etc.
Here are the links to the talks that I/we gave:
[
jonas
]
07:17, Friday, 19 March 2004
Today we released the 0.10 Release Candidate 1 of AspectWerkz.
Which forms the foundation for the next generation of AspectWerkz.
AspectWerkz has gone through a lot of changes, the whole core engine has
for example been thrown out and replaced by a much more flexible and
performant one. The join point model is much more expressive and
orthogonal we have also implemented a JIT compiler that is making
AspectWerkz much more performant. On top of that we have a new
implementation of true runtime weaving, which allows you to redefine
your aspect model including adding new pointcuts at runtime.
Read more about it here.
[
jonas
]
06:58, Friday, 19 March 2004
The AspectWerkz project is since a a month ago sponsored by BEA Systems.
Both Alexandre and I, the founders and primary contributors to
AspectWerkz, are full time BEA employees. I work with the JRockit
engineering team in Stockholm, and our primary objective is to make
AspectWerkz the leading AOP framework for dynamic AOP, and to ensure
that the JRockit JVM is far and away the best Java platform for AOP.
We are, of course, working on a number of interesting future directions
tight to the in tight coordination with the rest of the BEA products
line, but the near term goals are to build deep and unprecedented
support for AOP, including real-time run-time weaving into JRockit Java
Virtual Machine, and to make AspectWerkz on top of JRockit the number
one choice for dynamic AOP in enterprise application environments.
AspectWerkz still is and will remain open source software, licensed
under LGPL and will continue being platform and vendor independent.
[
jonas
]
11:16, Wednesday, 3 March 2004
I was lucky and our submission to JavaOne was accepted.
This means that Alex and I will do a presentation on "Dynamic Aspect-Oriented Programming in J2EE environments".
See you there.
[
jonas
]
09:32, Wednesday, 18 February 2004
Alex and I will do a half-day tutorial on AspectWerkz at AOSD 2004.
The tutorial will be an introduction to AOP/AOSD and AspectWerkz and to how it can be used in real-world enterprise applications.
It will include hands-on exercises and we will show you how to implement services like:
|