How to write Java EE / EJB Singleton?

A day ago, my application had one EAR containing one WAR, one EJB JAR, and a couple of utility JAR files. I had the POJO singleton class in one of these utility files, it worked, and everything was fine with the world:

EAR |--- WAR |--- EJB JAR |--- Util 1 JAR |--- Util 2 JAR |--- etc. 

Then I created a second WAR and found (the hard way) that each WAR has its own ClassLoader, so each WAR sees a different singleton, and everything breaks from it. This is not so good.

 EAR |--- WAR 1 |--- WAR 2 |--- EJB JAR |--- Util 1 JAR |--- Util 2 JAR |--- etc. 

So, I'm looking for a way to create a singleton Java object that will work through WAR (via ClassLoaders?). @Singleton EJB @Singleton looked pretty promising until I found that JBoss 5.1 does not seem to support this annotation (which was added as part of EJB 3.1). I missed something - can I use @Singleton with JBoss 5.1? Upgrading to JBoss AS 6 is not an option now.

Alternatively, I would be just as happy that I should not use EJB to implement my singleton. What else can I do to solve this problem? Basically, I need a semi-task * hook in a whole bunch of other objects, such as various cached data and application configuration information. As a last resort, I already considered the question of merging my two WARS into one, but that would be pretty hellish.

* Value: available mainly anywhere on a particular layer; at the moment, mainly in my WARs - View and Controller (in the free sense).

Edit: I really should call it Java EE , not J2EE, right?


Edit 2: Thanks again @Yishai for the help. After some trial and error, I seem to have figured out how to use one Loader class as part of WARs under JBoss 5. I am setting this out in detail below for myself, and hopefully others will find it useful. p>

NB this is slightly different from this in JBoss 4 (see Yishai answer or my links below).

Instead of writing jboss-web.xml for each WAR and jboss.xml for the EJB-JAR ear, put the jboss-classloading.xml in each WAR, in the same place as DD ( web.xml ). The content of jboss-classloading.xml should be:

 <?xml version="1.0" encoding="UTF-8"?> <classloading xmlns="urn:jboss:classloading:1.0" name="mywar.war" domain="DefaultDomain" parent-domain="Ignored" export-all="NON_EMPTY" import-all="true"> </classloading> 

This follows from JBoss CW here , whereas what (I think) works for JBoss 4.x is described here . More general information on downloading JBoss (ing / ers):

As far as I can tell, the JBoss community in the Wiki documents is pretty small for JBoss 5 compared to JBoss 4.

+7
java java-ee singleton ejb
source share
5 answers

Although the EJB3.1 specification represents a singleton, and your version of JBoss does not support it, you can use the JBoss @Service annotation to create a singleton. Instructions are here . Also, it looks like your JBoss is set to isolate banks and ejb wars from each other. You do not have to do this. You can look at the loader-repository tag in specific jboss xml files so that your whole ear is shared by one classloader (or, perhaps, at least two wars share the same classloader).

All that has been said, I agree with @duffymo that a singleton sharing a fortune between two wars is the idea that you should go if you don't run away.

Edit: Regarding singletones, I suggest you look at issues like this one (which also has a nice balance in the comments).

The idea of ​​having an object’s caching state is okay on its own, especially with EJB3, where you can enter your state rather than statically refer to it (if you use the @Service annotation, then you want the @Depends JBoss annotation). At the same time, if you used the "correct" singleton here, I would expect that your only problem with the fact that your WARs have two separate class loaders is the extra memory. Otherwise, you get into the problem area of ​​singletones (where they must be initialized for use, everything that uses them should ensure that they are initialized first, and, of course, all the code is strongly related to their initialization).

If singletones are really very bad, they store state, so one class can change state, and another class selects it. This is basically a no-no in EJB prior to 3.1, and even then it makes a lot of concurrency problems.

Edit (further): So you want to go with the classloader repository. I use JBoss 4.2.3, so I don’t necessarily know all the inputs and outputs of JBoss5 (which rewrote its class loader, although they say that it is almost completely backward compatible), however in 4.2.x your configuration doesn’t cause it by default because that all ears deployed on the server have the same classloader ("unified classloader"). I suspect that the server on which you are deploying has a different configuration, so I'm not sure that it can be contacted, but you need to add a file called jboss-app.xml in your ear (in the same place as and application.xml), which looks something like this:

  <?xml version="1.0"?> <!DOCTYPE jboss-app PUBLIC "-//JBoss//DTD J2EE Application 4.2//EN" "http://www.jboss.org/j2ee/dtd/jboss-app_4_2.dtd"> <jboss-app> <loader-repository> com.yourcomany:archive=yourear </loader-repository> </jboss-app> 

This is for JBoss 4.2. 5.1 has a tag of the same type, here is xsd . It has the same storage loader concept.

It should be like that. That is, as long as your ejb-jar, war, etc. They do not have it, then they do not need it. However, your wars (in jboss-web.xml - the same place as web.xml) may need the same. In this case, while you name the repository in exactly the same way (if I understand correctly, I never tried it myself), they will use the same classloader. The same goes for EJB, which is configured in jboss.xml, which is in the same place as ejb.xml.

This can make it a little clearer.

+11
source share

I would configure a separate pool of objects on your application server, so it contained only one instance.

Why would you like to do this is a real question. It looks like all your apps will be connected in this way. And Google destroys singleton from its apps. Why do you think it necessary to return it?

+1
source share

You can use the MBean and bind it to the JNDI, and then get it where you want to use it.

MBean can be deployed in a .sar file

+1
source share

If you use Java EE 6, then it supports singleton EJBs.

+1
source share

If this is practical, just take a class that has a singleton, put it in a JAR, take the JAR OUT from the EAR and add the JAR to the JBoss class loader (via the class system path or some lib directory), This puts the class in one class loader, common to both WARs.

Singleton will not be able to "see" anything in your WAR applications, etc., since they are in the lower classloader.

However, nothing prevents you from entering the singleton (at server startup) class factory, which comes from WARs et al, and the THAT class has access to all application classes. This makes singleton a simpler container.

But it is easy to do.

In addition, if you do, make sure that when you close the application, all instances stored in this singlet are freed. Any class reference to singleton will not be GC'd when you decompose the application. So, if you have a link to your application stored in singleton, then the server contains a link to the singleletons class loader, this class loader contains a link to your singleton class, which contains a link to your application class, which contains a link to CLASSLOADER applications , and THAT contains a link to all classes in your application. An unpleasant mess to leave behind.

0
source share

All Articles