I've been evaluating spring-dm over equinox for some time now. If your project already has invested in Spring then Spring-DM provides support for injecting dependencies across bundles and manages tx across bundle boundaries.
However the main feature of Spring-DM that I find actually useful is Springs support for OSGi services. Spring adds support for declarative publishing of services and consuming them. Any spring created bean can be published to the service registry using the xml tag osgi:service. Any service from the service registry can be references using the xml tag osgi:reference.
When you refer a service using osgi:reference, spring-dm creates a proxy over the service and injects the proxy into your code. This proxy protects the users of the service from the lifecycle of the service. So if the underlying service goes down, your code need not be aware that it should look up and bind to a new service.
The proxy is either a jdk dynamic proxy or a cglib proxy depending on whether the service has an interface or not. This proxy has a number of interceptors like transaction etc. Imagine the underlying service goes down, the next call to the proxy would trigger the proxy to check if service is up. If service is down, the proxy will block the call for a 'timeout' period at end of which a service unavailable exception is thrown. When a new service that matches the service for which the proxy is created, is registered, this proxy binds to that service and sends all queued requests to that proxy. Voila, your code is blissfully unaware a service went down and came up again.
However things are not all rosy. A couple of issues i faced
1) If the bundle that has the proxies is refreshed, the currently executing method throws an exception with message "service proxy destroyed". There is no way around this. Any new request that comes through would work fine.
2) We cannot add a custom interceptor to spring created proxy since it says configuration is frozen. So I had to create a proxy on top of springs proxy to add my custom interceptor. This is a fairly common case and should have been possible.
PS: The custom interceptor was created to transparently handle the service proxy destroyed issue.
Tags: OSGi, Spring-DM
Saturday, May 03, 2008
Spring-DM and OSGi Service Proxy
Posted by
Kaushik
at
12:04 PM
0
comments
Thursday, January 24, 2008
Troubles with OSGi - Part 1 - Proxy Creation Issues with Hibernate
We are trying out using osgi as a container for our application hoping to leverage it's dynamic updates and staged rollout features. Our system needs to be updated/rolledback with 0 downtime. Yeah we're working on *that* critical an application ;).
I have run into some pretty interesting issues using OSGi. There is not a lot of info on typical business applications that use OSGi. Some of the issues we faced were not documented and we had to get a lot of help from many forums. So the next couple of posts would be some stories around how OSGi was used and what pitfalls were faced.
All our code was packaged into small(er) osgi bundles. Following bundles were created -
- Bundle 1 - All entity classes,
- Bundle 2 - All business logic classes,
- Bundle 3 - All DAO's ,
- Bundle 4 - All client classes.
In initial stages I like to know how and why things work so that we can trouble shoot issues easily later. This made me decide against using the dynamic-imports feature. So every dependency needed by a bundle had to be manually declared in the manifest file.
Most of the initial issues got resolved quickly. But we started getting NoClassDefFoundError for HibernateProxy in our main bundle. This was really weird because the bundle that was executing the code, had imported all of spring's and hibernate's packages.
A couple of hours were spent trying to recreate the bundles, re-declare all the imports etc, but still no progress. I decided debugging was the best way to go forward. I got all spring/hibernate sources and started stepping through. Here's what I found.
Hibernate creates a proxy for any entity which does lazy loading. This proxy is a cglib based proxy that implements the HibernateProxy interface and also derives from the actualy entity object. When CGLIB is called to create a proxy, it creates a new class definition and creates the byte array representing the class. This class is then loaded onto the entity object's classloader.
However in OSGi each bundle has it's own classloader. So the entity bundle that contained only the POJO's had a classloader of its own and this bundle did not import any packages from any other bundle. The business code bundle imported the entity, hibernate and spring bundles and so the bussiness code bundle's classloader was wired with the other 3 classloaders. When CGLIB created the proxy and tried to define the proxy class in Entity bundle which did not import hibernate packages, it was throwing the NoClassDefFoundError.
The fix was to import this package in the entity bundle and things were all set. But this whole issue raised 2 main concerns
1) The stack traces raised by Equinox OSGi framework does not give detailed info on source of an error and just gives info on the initial bundle that was executing the code when error occured. Is this an issue with Equinox alone or is it same across all other osgi containers ?
2) Even though a bundle may not directly use a class, you may still have to import it (or) use dynamic-imports and be masked from this. Either way it's still ugly.
Tags: OSGi, Spring-DM
Posted by
Kaushik
at
9:14 AM
2
comments