Hi Mark,

OK - as a newbie I read this from the stack trace: ...

>20160713-161427.340 ERROR [catalina-exec-64] [] [[/]] StandardWrapper.Throwable
>[...]
>        at 
> org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
>        at javax.servlet.GenericServlet.init(Unknown Source)
>        at org.apache.catalina.core.StandardWrapper.initServlet(Unknown Source)
>        at org.apache.catalina.core.StandardWrapper.loadServlet(Unknown Source)
>        at org.apache.catalina.core.StandardWrapper.allocate(Unknown Source)
> 2)    at org.apache.catalina.core.StandardWrapper.isSingleThreadModel(Unknown 
> Source)
>        at sun.reflect.GeneratedMethodAccessor178.invoke(Unknown Source)
>        at 
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>        at java.lang.reflect.Method.invoke(Method.java:497)
> 1)    at org.apache.tomcat.util.modeler.BaseModelMBean.getAttribute(Unknown 
> Source)
>        at 
> com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getAttribute(DefaultMBeanServerInterceptor.java:647)
>        at 
> com.sun.jmx.mbeanserver.JmxMBeanServer.getAttribute(JmxMBeanServer.java:678)
>        at org.apache.catalina.mbeans.MBeanDumper.dumpBeans(Unknown Source)
 [...]

It seems to me that "all reading is passiv" don't hold because the call to 
getAttibute() at 1) will invoke the MBean and this leads to the call of 
isSingleThreadModel at 2) -- I don't see why at the moment.

But about 2) I take a look at the sources at github:


public boolean isSingleThreadModel() {

        // Short-cuts
        // If singleThreadModel is true, must have already checked this
        // If instance != null, must have already loaded
        if (singleThreadModel || instance != null) {
            return singleThreadModel;
        }

        // The logic to determine this safely is more complex than one might
        // expect. allocate() already has the necessary logic so re-use it.
        // Make sure the Servlet is loaded with the right class loader
        ClassLoader oldCL = null;
        try {
            oldCL = ((Context) getParent()).bind(false, null);
--->        Servlet s = allocate();
            deallocate(s);
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
        } finally {
            ((Context) getParent()).unbind(false, oldCL);
        }
        return singleThreadModel;
}


And this will load (and initialize) the servlet because some conditions are 
fulfilled: It is sure that  singleThradModel == false  and  instance == null  
because we are called from isSingleThreadModel

So maybe there should be a special code path in case of an ongoing 
initialization on the top like the 'if(unloading)' clause. The note states, 
that one can't decide if a Servlet implements SingleThreadModel until loading. 
So maybe on startup this must be answered in a "conservative way" (if possible) 
or thrown back with an exception. If this will lead to an overall exception for 
the MBean request, this might be "the right thing", because at leaset one of 
the returned information can't be answered yet at this moment (during 
initialization of the servlet).


    @Override
    public Servlet allocate() throws ServletException {

        // If we are currently unloading this servlet, throw an exception
        if (unloading) {
            throw new 
ServletException(sm.getString("standardWrapper.unloading", getName()));
        }

        boolean newInstance = false;

        // If not SingleThreadedModel, return the same instance every time
        if (!singleThreadModel) {
            // Load and initialize our instance if necessary
--->        if (instance == null || !instanceInitialized) {
                synchronized (this) {
                    if (instance == null) {
                        try {
                            if (log.isDebugEnabled()) {
                                log.debug("Allocating non-STM instance");
                            }

                            // Note: We don't know if the Servlet implements
                            // SingleThreadModel until we have loaded it.
                            instance = loadServlet();
                            [...]


By the way: The only occurrence where  instaceInitialized is set to true is 
*after* a call to the core servlet.init at initServelt. Therefore it semantic 
is not "initialization is started and in progress" but "initialization is 
completed" and IMHO therefore one can't take it as an indicator for the fact 
that's it should be done. But I can't overview if the  synchronized(this)  will 
close this gap. 



Greetings

Guido

Reply via email to