Monday, June 6, 2011

Spring, JPA, Java EE, JBoss: deployment strategies

Last week I made a comment on Michał's post - which I strongly recommend, by the way - where I alluded to the possibility of using an entity manager factory created by the application server instead of using the local JPA entity manager factory beans. Since I have been asked to provide a more detailed description, I will do this in a separate post, as doing that within the comment space is rather difficult, especially when providing code samples. The context of this discussion is the JBoss Application Server, but most of the considerations apply for other Java EE-compliant application servers as well.

Automatic creation of entity manager factories in JBoss

When using Spring and JPA in a servlet container, developers can create an EntityManagerFactory by using a LocalEntityManagerFactoryBean or a LocalContainerEntityManagerFactoryBean. In such an environment, it is pretty much the only option available. In JBoss, they can still do that, or they can choose to rely on the application server to create such an EntityManagerFactory for them.

Typical JPA applications will contain a META-INF/persistence.xml file which contains the persistence unit definition. JBoss, as a full-fledged Java EE application server, will deploy the persistence unit (and therefore create a EntityManagerFactory), whenever such a file is present in the deployment. So, unless special steps are taken to prevent that from happening (more about that below), the EntityManagerFactory will come into existence automatically. As a side note, you are required to use JTA in this case, as Java EE does not support the deployment of persistence units with the RESOURCE_LOCAL setting. If you are worried about how JTA will affect your performance however, please note that JBoss will optimize transaction management in single-resource scenarios, so any overhead is hardly significant.

So, once you provide a META-INF/persistence.xml file with your application, there is no actual need to create a new EntityManagerFactory in Spring, but you still need to create a reference to the container-managed entity manager factory which you can further inject that into your DAOs, and you can do that through a JNDI lookup. In order to do so, you need to register your EntityManagerFactory in JNDI. Web applications can do this by adding this to their web.xml file.

Adding a persistence unit reference to web.xml


Once this is done, the entity manager bean definition can be:

And that is it. JBoss will deploy the persistence unit automatically and you can reference it directly, without the need for creating a new one.

What if I don't want to use the container-managed entity manager factory?

Since the persistence unit deployment process takes place automatically, if you don't want to use the container managed entity manager factory and instead opt for creating a Spring-based one, you need to prevent JBoss from doing the deployment. This can be done in a number of ways - either by renaming the persistence unit file and using the 'persistenceXmlLocation' atrribute as shown below.

Using an alternative persistence definition location


You can also use the META-INF/jboss-ignore.txt file as an alternative to renaming. Simply create such a file and include the line below.

The wrap-up

When using Spring and JPA on JBoss, you can opt between the following strategies:

  1. Container-managed entity manager factory + JTA transactions - requires the least amount of configuration to set up, and it is based on functionality supplied automatically by the application server. It is worth keeping in mind that in a clustering scenario, this option ensures that the configuration for distributing the secondary-level cache will be automatically provided by the application server. 
  2. Spring-managed entity-manager factory + JTA transactions - still using JTA, requires additional configuration for setting up the application server. This is an option to consider if your application uses @Transactional(readOnly=true), as container-managed EntityManagerFactories will not honour that option.
  3. Spring-managed entity-manager factory + local transactions - works in an identical way is an a servlet container.