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