If it helps for reference.... Here is our singleton...

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathFactoryConfigurationException;

/**
 * This class provides a set of methods to obtain a shared instance of various 
pre-configured XML parser factories. This
 * is intended to avoid searching the classpath when looking for an 
implementation of a factory. Using an enumeration to
 * create a shared instance guarantees a thread-safe singleton since the 
enumeration itself ensures internally that only
 * a single instance is available. Each singleton instance is constructed when 
the enumeration is referenced for the
 * first time. Configuration of a these factories is not expected to be thread 
safe; an application programmer should
 * not allow an instance of this factory to have its setter methods accessed 
from more than one thread.
 */
public final class XMLFactory {

    private enum DocumentBuilderFactorySingleton {
        SINGLETON;

        public final DocumentBuilderFactory instance;

        private DocumentBuilderFactorySingleton() {
            instance = DocumentBuilderFactory.newInstance();
        }
    }

    private enum TransformerFactorySingleton {
        SINGLETON;

        public final TransformerFactory instance;

        private TransformerFactorySingleton() {
            instance = TransformerFactory.newInstance();
        }
    }

    private enum XPathFactorySingleton {
        SINGLETON;

        public final XPathFactory instance;

        private XPathFactorySingleton() {
            instance = XPathFactory.newInstance();
        }
    }

    private XMLFactory() {
        return;
    }

    /**
     * This method returns a shared instance of a default document builder 
factory. Do not call any setter methods on
     * this shared instance. If an alternative configuration is necessary, a 
new factory should be created.
     * @return shared instance of document builder factory
     */
    public static final DocumentBuilderFactory 
getDocumentBuilderFactoryInstance() {
        return DocumentBuilderFactorySingleton.SINGLETON.instance;
    }

    /**
     * This method returns a new instance of a document builder factory.
     * @return new instance of document builder factory
     */
    public static final DocumentBuilderFactory 
newDocumentBuilderFactoryInstance() {
        return 
DocumentBuilderFactory.newInstance(getDocumentBuilderFactoryInstance().getClass().getName(),
 null);
    }

    /**
     * This method returns a shared instance of a default transformer factory. 
Do not call any setter methods on this
     * shared instance. If an alternative configuration is necessary, a new 
factory should be created.
     * @return shared instance of transformer factory
     */
    public static final TransformerFactory getTransformerFactoryInstance() {
        return TransformerFactorySingleton.SINGLETON.instance;
    }

    /**
     * This method returns a new instance of a transformer factory.
     * @return new instance of transformer factory
     */
    public static final TransformerFactory newTransformerFactoryInstance() {
        return 
TransformerFactory.newInstance(getTransformerFactoryInstance().getClass().getName(),
 null);
    }

    /**
     * This method returns a shared instance of a default xpath factory. Do not 
call any setter methods on this shared
     * instance. If an alternative configuration is necessary, a new factory 
should be created.
     * @return shared instance of xpath factory
     */
    public static final XPathFactory getXPathFactoryInstance() {
        return XPathFactorySingleton.SINGLETON.instance;
    }

    /**
     * This method returns a new instance of a xpath factory.
     * @return new instance of xpath factory
     * @throws XPathFactoryConfigurationException
     */
    public static final XPathFactory newXPathFactoryInstance() throws 
XPathFactoryConfigurationException {
        return XPathFactory.newInstance(XPathFactory.DEFAULT_OBJECT_MODEL_URI,
                getXPathFactoryInstance().getClass().getName(), null);
    }

}

-----Original Message-----
From: Niall Fitzpatrick <niallfitzpatr...@live.co.uk>
Sent: Tuesday, January 14, 2020 11:48 AM
To: Tomcat Users List <users@tomcat.apache.org>
Subject: Re: Class loader takes long time after server inactivity - Tomcat 
Version 9.0.10



________________________________
From: Christopher Schultz <ch...@christopherschultz.net>
Sent: 14 January 2020 16:30
To: users@tomcat.apache.org <users@tomcat.apache.org>
Subject: Re: Class loader takes long time after server inactivity - Tomcat 
Version 9.0.10

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Mark,

On 1/14/20 9:58 AM, Mark Thomas wrote:
> On 14/01/2020 14:40, Niall Fitzpatrick wrote:
>>
>>
>>
>>
>>> Hi Folks,
>>>
>>>
>>>
>>> I have a web application that, after a period of inactivity
>>> (1-2hours), will stall for 3 - 35 seconds upon the first new
>>> session. All subsequent sessions will not experience this delay
>>> unless another period of inactivity occurs.
>>>
>>>
>>>
>>> I've found that the delay occurs when loading jars that live in the
>>> WEB-INF/lib folder.
>>>
>>>
>>>
>>> The issue doesn't occur when the server is first started. Only after
>>> a period of 1-2 hours approx. will the next session experience the
>>> delay when loading a jar. This leads me to believe that when the
>>> server is started 'knowledge' of the jars might be cached, however,
>>> after a period of inactivity this cache may expire. The result of
>>> this is that the next session after this period causes the lib
>>> folder to be searched again which seems to take the 5-35 seconds.
>>>
>>>
>>>
>>> My question: Is this theory above correct, and if so, is there a way
>>> to configure Tomcat such that this cache doesn't expire so that it
>>> doesn't need to be re-populated when a new session begins?
>>
>> It depends. Which resources are slow to load?
>>
>> Mark
>>
>> Hi Mark,
>
> Thanks for the additional info. That helps a lot.
>
> Apologies for the following information dump but there are lots of
> factors to make you aware of.
>
>> Doesn't seem to matter which Jar. At first it happened when loading a
>> class from my own custom Jar.
>
> That should be a one-time cost. Once loaded, classes remain in memory
> until the web application is stopped.
>
> Finding the right class can be expensive. The more JARs the
> application has, the more expensive the process will be. Tomcat does
> cache the list of entries in a JAR for a short period of time to speed
> up this search. If the application has been completely idle for a
> while then you will see a pause on the first attempt to load a class
> while those caches are refreshed.
>
> Tomcat can't hold the cache for too long as it uses memory and locks
> files.
>
> One possible solution is to use a ServletContextListener and load the
> classes you know will be / are likely to be required when the
> application starts.
>
>> I removed this code to determine if it was the cause. However, then I
>> found the same problem further downstream. When calling
>> DocumentBuilderFactory.newInstance() which lives in
>> xml-apis-1.3.04 The delay of 5-35 seconds occurred here instead.
>
> Ah. That will probably be the biggest culprit.
> DocumentBuilderFactory uses an SPI mechanism to find the correct
> instance to create. That SPI mechanism involves searching every JAR
> for a configuration file. The expectation, although it may not be
> documented as clearly as it should, is that
> DocumentBuilderFactory.newInstance() is called only once during the
> lifetime of a web application and the result cached.

+1

But 5-30 seconds is a looong time.

Niall, any chance you have a particularly slow disk, loaded server, or maybe a 
network share where these files are located?

- -chris


Hi Chris,
I don't believe so. A customer reported the issue, and I was able to recreate 
it on our own test environment. I will say this - the web application has 263 
jars in it's lib folder. That's got to be a lot of searching.

Thanks for everyone's suggestions. I'm going to try the wrapper class solution 
where I can cache the result. I'll send an update with what I learned.

Niall

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



CONFIDENTIALITY NOTICE This message and any included attachments are from 
Cerner Corporation and are intended only for the addressee. The information 
contained in this message is confidential and may constitute inside or 
non-public information under international, federal, or state securities laws. 
Unauthorized forwarding, printing, copying, distribution, or use of such 
information is strictly prohibited and may be unlawful. If you are not the 
addressee, please promptly delete this message and notify the sender of the 
delivery error by e-mail or you may call Cerner's corporate offices in Kansas 
City, Missouri, U.S.A at (+1) (816)221-1024.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to