Tuesday, October 24, 2006

more on aspects

I did more experimentation with aspectj today. I really dig the idea, but I'm hesitant to recommend something where there is a large compilation time impact, or runtime impact. Yesterday I used the eclipse dev tools for aspectJ. Pretty neat, but the additional compile time seems a bit heavy. So, I moved to try the LTW- the weaver piece, that allows you to add advice to classes as the classloader loads them. Theres lots of docs on this on the web, but here's some notes that might help.

1. Seems if you're using the eclipse aspectJ tools, having a seperate project for the aspects is the best way to set things up. Then, when you change the aspects, just export the jar into your web-app\lib directory.

2. You'll need to customize the aop.xml file some. Heres mine. Basically you make a directory in your "jar" project called META-INF, and create a file called aop.xml. The aspect j weaver will read this, and now what aspects to "weave" in. Mine is later in this document.

3. When you run your classes(a unit test perhaps), you'll need to add the following stuff. I was just using eclilpse, so tomcat or appserver setup would of course be different.
Notable JVM args:

-- if you want to override the default aop.xml file locations:
-Dorg.aspectj.weaver.loadtime.configuration=myclasspathplace/aop.xml;foo/bar/aop.xml

-- this will give you info as to the parsing of the aop.xml file

-Daj.weaving.verbose=true

finally, in order to do the LTW:
-javaagent:./lib/aspectjweaver.jar -Xmx256m

Note I added the JVM args as I was running out of memory. I also had some wierd errors when I first started, and had to upgrade my aspectweaver.jar, from something newer than 1.5.2. Basically a null pointer exception in the weaver...


So, here are the issues:
The weaving adds about 30 seconds of additional startup time, even with the many exclusions below. Note that my advice doesn't do a whole lot.

Unittest (200 tests) time w/out :45 seconds
With weaver was about 75 seconds
With compilation time (non LTW) about 44 seconds.

Maybe later this week I'll now tell spring about my aspects...
At the moment I'm not sold on using aspects in daily development. Maybe as part of an automated build it would be okay, but that kind of limits what I would do with them in the first place it seems.















































crazy for aspects

I stayed up too late into the evening trying to learn aspectJ. I think we should consider its use more often. It makes things like logging simple.
Note that it requires that you modify your eclipse environment to have the aspectj compiler. Or, download the eclipse tools here:
download aspectj developer tools

Then watch this quick demo:
demo of aspectj tools

What I like most about the tool, is that it shows you where your advice will be applied!

** Note, if you are using BEAWorkshop, for some strange reason BEA doesn't include the PDE plugins for eclipse, and although the tool(ajdt) will be installed, it didn't work for me, until I manually added this plugin via the eclipse software update function.

The real time consuming thing is to figure out how to define pointcuts (where your code will run), and the aspectj syntax. Hopefully my samples will make it easy.

Here's some sample aspects I wrote:

public aspect ServiceLayerAspect {
/**
* intercept executiong of methods begining w/ pkg name com.service, ending with name service
* and any method
*/
pointcut methodsEndingWithNameService():
//any pkg or subpackage of service
within(pkg.pkg.pkg..*)
// && execution(public * pkg.pkg.pkg.*.*Service.*(..))
//classname ends in Service
&& execution(public * com..*Service.*(..))
&& !execution(public * get*())
&& !execution(public void set*(..))
;

before(): methodsEndingWithNameService() {
Logger log = Logger.getLogger(thisJoinPointStaticPart.getSignature().getDeclaringType().getName());

log.debug("before service method "+thisJoinPointStaticPart.getSignature().getName());
}
}




public aspect DomainLayerBusLogicLogger {
/**
* intercept executiong of methods begining w/ pkg name com.service, ending with name service
* and any method
*/
pointcut methodsNotGetSet():
// call(public * get*(..));
// &&
within(pkg.pkg.domain..*)
&& execution(public * *(..))
&& !execution(public * get*())
&& !execution(public void set*(..))
;

before(): methodsNotGetSet() {
Logger log = Logger.getLogger(thisJoinPointStaticPart.getSignature().getDeclaringType());
log.debug("bus domin method:"+thisJoinPointStaticPart.getSignature().getName());
}
}


public aspect StrutsLoggingAspect {
/**
* find methods that return an ActionForward, and extend DispatchAction
*/
pointcut dispatchingActionForwards():
execution(public org.apache.struts.action.ActionForward
org.apache.struts.actions.DispatchAction+.*(..));

before(): dispatchingActionForwards() {
Logger log = Logger.getLogger(thisJoinPoint.getTarget().getClass());

log.debug("Web action start:"+thisJoinPointStaticPart.getSignature().getName());
}

Sunday, October 22, 2006

Hibernate inner workings 1

Although I've been Hibernating for a couple of years now, it seems there is always more to know. I'm a big fan of hibernate as its allowed me to apply what I learned long ago in all my OO classes w/ CRC cards. It really is possible to put Domain Model Programming into practice. Okay, so why am I writing about it today? Because I finally looked at the source to see how it does change detection. Any object loaded by HIbernate, is "watched" by hibernate for changes. I knew this, but didn't really know how it works. So, from my brief look at the code, heres how it goes AFAIK

  1. You load objects via load, get, query, whatever
  2. Hibernate puts these objects in its session cache (a hashmap)
  3. Hibernate uses the key of the object and the class to as the key
  4. When sess.flush is called (either explicitly or because tx is finished or a query is executed)
  5. Hibernate goes throught its identitymap of object
    1. Check out the FlushEventListener class for details
  6. The EntityEntry for the object is found
  7. Dirty check takes place against the EntityEntry. Each EntityEntry has the loadedState of an object, which appears to be an array of simple properties
  8. Update is scheduled if necessary
I initialially thought hib did all this via CGLIB. Appears I was incorrect. Also, if you think your equals methods are involved in this evaluation, that appears to not be true either.

Cheers, long live hibernate

--James