I recently embarked on some Spring “re-training” (I haven’t looked at it in a few years and it was time to get my skills up to scratch again). Since the last time I looked at Spring, I have worked on a couple of rich (thick) client projects where it was almost impossible to find people with both server skills and GUI skills (the market is quite good at the moment and people like me with all those skills get snapped up very quickly ).
Anyway, since it is hard to find strong GUI programmers who also know how to deploy an app server and start it, it becomes desirable to be able to run the services inside the same JVM as the GUI programmer is developing in. There is then no wasted time due to EJB configurations and all the crap that comes with server development.
About 18 months ago, I got around the problem by quickly implementing a clever service locator. It worked brilliantly, the only real problem being that we had a few bugs because people had developed code which worked when services were local but not when they were remote. The effort in fixing those bugs was however minimal.
On my current project, we are using a proprietary framework based on Inversion of Control and Dependency Injection. Based upon its configuration, a client can call services locally or remotely too. If calling services remotely, they are invoked inside a stateless session bean which uses reflection and proxies in order to load the service and call its method. Transaction and security inteceptors are also in place ensuring that the services are called in the correct context. It is all very clever, but sadly proprietary (although at least we have the source code!).
Anyway, so as I am reading up on Spring, I am reminded how it too is intended to provide services independently of the environment in which it is running (that is, whether it is running in a stand alone application, inside a web container or an EJB container).
However, there is a marked difference compared to my Service Locator solution and the proprietary solution of my current project. In Spring, services are not automatically “remoted”. To move services from a standalone application to run inside an EJB container, you need to write code which sits between the client and those services to allow them to be called.
In EJB 3.0, a stateless session bean is simply a POJO. If it is not deployed in a server, a standalone application which has that POJO on its classpath can call a method in the POJO (admittedly without security or transaction functionality).
In Spring, you deploy your service to a Web or EJB Container and that container can use the services, but the client is no longer able to call those services. At the best, you can “remote” your service so that it can be called through its interface, however, it will live inside the web container. If you want the client to be able to call your service that is now in the EJB container, you need to write an EJB with the correct interface to expose that services functionality.
Now, is that a problem? What’s wrong with just using the web container or indeed just a web server? Ahhh… its not capable of handling transactions, I hear you say. True, but Spring provides mechanisms for applying a transactional context to your services. You can even use the transaction manager from your application server, so it will provide the same transactional functionality as provided to EJBs (for example XA compliant and having the ability to run across nodes in a cluster).
OK, OK, the web container doesn’t provide security to service methods! Well, also not true, since you can use declarative and programmatic security from the web container to ensure the user can only use functionality for which they are authorised.
OK, but the web container isn’t scalable/reliable/robust! Also not true, just like the EJB container, it has the ability to synchronise state across a cluster. And running in a cluster also means it is scalable, reliable and robust.
So, you might now start to agree, that actually, there is no need to run in an application server. Everything you do day in and day out can now be handled by Spring in the web container, ie. by a friendly cluster-aware web server like Apache Tomcat…
I wouldn’t disagree with that statement. However, here are some reasons to run inside a full application server:
- You need a JTA Transaction manager capable of propagating transactions across nodes in a cluster,
- The enterprise architecture department in charge of specifying the environment you run in is also capable of specifying that services must run in the EJB layer,
- You need to receive JMS messages in message beans
- You need to use Timer Beans
- You need a clustered JNDI tree as provided by your application server
- You need access to resources which your application server can provide and manage (eg. JCA)
If you don’t have any of these constraints, and you are committed to using Spring, then I currently do not see many reasons to run in anything other than a Web Container. If you can think of other reasons to run in a full application server, please leave comments below.