Sunday, February 11, 2007

Java, Component Models and Class Loader Hell

I've been drawn back to TSS again. There is an interesting thread where Bill Burke from JBoss-Seam goes head to head with Rod Johnson of Spring. Now it doesn't surprise me that Rod Johnson is a bit of an egocentric jerk - I know someone who worked him for years who told me as much. It was interesting though to see the JBoss guys break their usual aloof pseudo-intellectual demean a: read here.

Both of these frameworks claim to provide a component model for Java objects. So the first thing to clear up is what is a component? Well as far as I can tell, a component is a course grained object that can be bound to other coarse grained objects after compile time. So components are an invention for static OO languages, in dynamic OO, all objects are components.

Right with that out the way (anyone who is still not convinced, I would suggest exploring the runtime differences between a virtual function call as used in C++/Java/C# etc and polymorphic message sends as used in Smalltalk, Phython, Ruby etc), here is why do I believe that EJB's are a flawed component model.

Let’s take a simple example. Component A uses Component B. A configures B and registers a number of callbacks with B so that B can notify A. A is packaged in its own EAR (or 'war' or 'ejb-jar') and so is B. So what is the problem?

Well A must have access to the Interface of B, I will call this B' and B must also have access to the callback interface of A, which I will call A'. So there is a mutual dependency between A' and B'. With the J2EE class loader model, each component has it's own class loader (CL). Class loaders are arranged hierarchically. So the CL for B can be a dependent of the CL for A, or visa-versa, but two class loaders cannot be mutually dependent.

So you cannot have A<-->B relationships between J2EE components. Apparently OSGi is meant to be addressing this, but it seems a pretty fundamental language flaw to me. It will be interesting to see how they plan to get over this one!


Oh, yes I forgot Spring. Well IoC is nothing new. It allows you to separate interface from implementation, deferring binding untill runtime (back to message sends versus virtual function calls again). So again, by default all dynamic OO objects have this property. In Java it can be achieved with the use of an Interface and the reflection API, which is effectively what the Spring bean factory does. Fortunately Spring doesn’t go in for this separate class loader nonsense - so no class loader hell here - but if you choose to package your Spring application into a WAR, then you have no runtime binding of components either, so A<-->B, with Spring becomes AB. So if you want to change implementation to A<--->C at deploy time, where C implements B' you can't.

So it turns out that Spring isn't a component model at all - oh dear!

So neither of these so-called "Component frameworks" can do what Smalltalk did out of the box, over 30 years ago. Maybe they should have discussed this poignant fact on TSS, instead of squabbling like school girls.

Paul.

3 comments:

Peter Kriens said...

As you have already indicated, OSGi is the solution to both issues.

OSGi has a package based delegation model for class loaders which trivially solves the mutual dependency problem of A and B. OSGi even allows A-B to share a package and C-D share the same package but another version. At the same time it checks the consistency of the class spaces for each bundle. Interestingly, the type information in the language allows us to provide quite a few guarantees.

Spring never intended to be a component model so it is not fair to blame it not for being one. However, during the last year they worked on specifying how Spring and OSGi work together and that turns out to work very well because OSGi provides the missing parts of Spring, and the OSGi can use the configuration flexibility of Spring.

I am a fervent smalltalker and prefer dynamic languages over statically typed languages. However, for large systems where you get legacy parts from all over the place there is something to say for type information ...

Kind regards,

Peter Kriens
http://www.aqute.biz

Paul Beckford said...

Hi Peter,

Thanks for the info on OSGi. I'll take a look. BTW if the solution is trivial, why as no one done it before now?

I like to feel that I'm not bigotted over language choice either, and Java (with some tweaks) has definately got it's place.

I guess this post is best read in the context of my previous post on Java and denail. This stuff is uncommon knowledge amongst most Java programers. So my goal was to shed some light for the uninitiated.

BTW, large systems and types? I'm open minded on this. Incidently dynamic languages and compile-time type checking are orthogonal concerns and can be considered complimentry. Take a look at Strongtalk which Sun bought and buried.

What motivates me is that there has been a lot of marketing driven miss-information about types, objects, components etc. IMO we have passed up on many of the best ideas, and most programmers just aren't aware of what exists in the 'archive'.

BTW what is Spring? I've read Rods early books on J2EE and EJB's and he was definately right back then. Today though, Spring seems to be more of a Marketing label than a concept. All things to all men perhaps?

Paul.

Steve Zara said...

"It allows you to separate interface from implementation, deferring binding untill runtime (back to message sends versus virtual function calls again)"

No, this is not what IoC does at all. It is not about deferring things in time (until runtime). It is about separation of concerns. It means that you avoid explicit construction of instances of specific classes throughout your code. What IoC allows is that construction to be handled elsewhere (separate from the business logic), so that you can substitute subclasses or alternative implementation of interfaces, to change functionality or to test. IoC is all about separating logic from glue code. It is entirely feasible to have all of the IoC expressed in pure, compiled, statically typed code.