This post originated from an RSS feed registered with Java Buzz
by Brian McCallister.
Original Post: Intercept .1.2 Release
Feed Title: Waste of Time
Feed URL: http://kasparov.skife.org/blog/index.rss
Feed Description: A simple waste of time and weblog experiment
A comment I missed a while back asked about the performance of Signature.matches(...). Bo's concern was that calling this on every interceptor on every invocation would be painfuly slow. Rest easy, this isn't done. The broker builds match information when the interceptor is added and when a new class (not new instance, just new class) is first wrapped. It caches the interception information on a per-class/per-method basis so that the invocation sequence looks like:
foo.doSomething()
ServiceHandler.intercept(...) { query this.methodInterceptMatrix for interceptors for this method }
MethodInterceptMatrix.interceptsFor(...) { hash lookup for interceptors for a method. This might be able to be optimized to an array index lookup instead of a hash lookup, but I haven't had a chance to investigate yet. }
ServiceHandler.intercept(...) { back here, create a new InterceptorStack and return stack.yield() }
Stack.yield() { Your interceptors here }
The MethodInterceptMatrix is key as it allows a hash lookup speed interceptor stack generation (plus interceptor instantiation time for the "new interceptor for every invocation" style interceptors). As mentioned, I am pretty sure I can reduce this to an array index, but havent had time/need to do so yet. The MethodInterceptMatrix is responsible for keeping track of what interceptors care about what methods and builds this information when new interceptors are added, or when new MethodInterceptMatrix instances are created when a class is generated.
The benefit to this design is faster interceptor stack invocation. The drawbacks are that adding a new interceptor to a broker with a lot of classes registered is slow, and adding a class to a broker with a lot of interceptors is slow. An additional drawback is that you only have java.util.reflect.Method information in the Signature.matches(...) test. There have been cases where I want to match calls against a specific instance only intead of all calls to that type's method. This has to be filtered at invocation time (as Bo was afraid of) so needs to be done in the interceptor instead of the Signature which is ugly =/ I have thought about splitting signatures into two types -- compile-time and invocation-time in order to make this cleaner, but haven't yet as I haven't had the need and no one has asked for it.