0

I discovered an interesting, may be wrong behaviour in Websphere Liberty / JEE 7, which I like to discuss if this is a bug or a feature.

First, the code described is an older Project which I have taken over, and the code is not always the fanciest or best way to do something. So let's get to the point: There is a utility-jar, which contains a ServletContextListener. The Listener performs the log4j initialization that way, that it has a final static variable that causes log4j initialization, when the class is loaded the first time.

The maven build produces two WARs, where each WAR contains the utility-jar containing the ServletContextListener. See the following graphic in order to see the structure of the EAR:

Structure of my EAR

This means I have two webapps containing the same utility-jar, which contains a static initilizer like this:

private static final MyLogger LOG = Logger.getLogger("webapp-1");

And here is my point: When I deploy it on Liberty with standard classloader policy (parentfirst), that static initialization takes place only ONE TIME! When using parentLast Policy, static initialization hapens TWO TIMES.

I have discussed this with a colleague who first said, that's OK. But thinking of it more and more, we came to mind that this behaviour is actually wrong. There is no way, where webapp-1 is finding any class which is part of webapp-2 or vice versa. That's why the static initialization (i.e. Classloading) must occure for each webapp separately. No matter which classloading policy, because Liberty does not have a log4j.jar on its Own.

So, what the heck has the classloader policy to do with that? In my oppinion it should have nothing to do with that.

What do you think? Is it a bug in Liberty, is it by design/intend (explanation, please) or what is it?

Please note, I am not looking for a solution, there are plenty. I am just interested, how other developers think on this topic.

The issue seems to affect only static members of classes. Because the log4j initialization is static, it is a matter of log4j is initializing for each webapp or initializing only once (the webapp which is loaded first).

You can check this, by using a utility class from a separate jar, which has a static member which is initialized statically. With parentFirst policy, it will be initialized only one time. And this should not be, afai understand.

********** Addition, inspired by Andy McWright ***** parentFirst: [25.07.17 15:24:39:405 MESZ] 00000063 id=40ad88b3 lassloading.internal.ContainerClassLoader$SmartClassPathImpl > getUniversalContainersForPath Entry
[user.dir].m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar [25.07.17 15:25:02:880 MESZ] 00000063 id=0f48e3d8 com.ibm.ws.classloading.internal.AppClassLoader > findOrDelegateLoadClass Entry
org.apache.log4j.Logger

parentLast: [25.07.17 15:46:38:580 MESZ] 00000064 id=1d3c9ea4 lassloading.internal.ContainerClassLoader$SmartClassPathImpl > getUniversalContainersForPath Entry
[user.dir].m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar, [25.07.17 15:46:20:471 MESZ] 00000064 id=70f6cf68 com.ibm.ws.classloading.internal.ParentLastClassLoader > loadClass Entry
org.apache.log4j.Logger [25.07.17 15:46:20:471 MESZ] 00000064 id=70f6cf68 com.ibm.ws.classloading.internal.AppClassLoader > findClass Entry
org.apache.log4j.Logger [25.07.17 15:46:20:471 MESZ] 00000064 id=70f6cf68 com.ibm.ws.classloading.internal.AppClassLoader > findClassBytes Entry
org.apache.log4j.Logger [25.07.17 15:46:20:471 MESZ] 00000064 id=70f6cf68 com.ibm.ws.classloading.internal.ContainerClassLoader > findBytes Entry
org/apache/log4j/Logger.class [25.07.17 15:46:20:471 MESZ] 00000064 id=1d3c9ea4 lassloading.internal.ContainerClassLoader$SmartClassPathImpl > getByteResourceInformation Entry
org/apache/log4j/Logger.class [25.07.17 15:46:20:471 MESZ] 00000064 id=1d3c9ea4 lassloading.internal.ContainerClassLoader$SmartClassPathImpl > getUniversalContainersForPath Entry
org/apache/log4j/Logger.class


Yes, Classloading is different. The question is, is this correct? I don't think so, I think it is a flaw.

Rambler
  • 1
  • 1
  • Can you enable -verbose:class (this is a JVM option) and run both tests to see where the Logger class is getting loaded from? I suspect that the Logger class may also exist in a parent classloader (perhaps in the EAR or shared library, or a Liberty feature, etc.) - then in parent first delegation, it would be loaded from that parent loader and only initialized once. Then in parent last, the class would be loaded by each WAR, thus initialized twice. The -verbose:class would tell you where the class was loaded from. HTH, Andy – Andy McCright Jul 25 '17 at 12:18
  • As per @AndyMcCright, check that your EAR does not contain additional copies of the utility.jar and log4j - possibly because of a bug in your build. – Steve C Jul 25 '17 at 12:50
  • Edited the post, added Classloader logs. Steve C, you are so right. There was skinnyWars active in the maven ear plugin, that is why I have log4j.jar in the ear/lib directory! I will try without skinny war and come back again. – Rambler Jul 25 '17 at 14:07
  • Thank you Steve, for providing a much better solution that I had. Without building a "skinny War" it is indeed unimportant which classloader policy is used. The static initializers are run separately for each war, like it is supposed to. The conclusion for me is, that skinny wars are not a good idea, because it may interfere classloading causing odd results. – Rambler Jul 25 '17 at 14:35
  • Anyway, if you build skinny wars, you must have classloader policy parentLast. – Rambler Jul 25 '17 at 14:48
  • 1
    I wouldn't say that skinny wars are bad per se, but they do have a different behavior. By putting the classes in the EAR, they are shared amongst all child (WAR/EJB) modules - that can be useful for reducing footprint, but it also means that you cannot re-use those modules in other EARs unless those EARs also contain the same required classes. In general, I would advise against using parentLast. There are some cases where it comes in handy, but more often than not, it causes more problems than it solves. Thanks, Andy – Andy McCright Jul 25 '17 at 16:06

0 Answers0