简体   繁体   中英

Lazy classloading in spring-mvc

I hava a project on Wildfly 8. So in it i have 1 war application, and many sar applications. In war i have controllers for managing entities, which are disposed in sar. mvc-dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd" default-lazy-init="true">
    <context:component-scan base-package="com.a1s.assist.web"/>
    <mvc:annotation-driven/>

</beans>

web.xml

<servlet>
    <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>0</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/mvc/*</url-pattern>
</servlet-mapping>

<context-param>
    <param-name>parentContextKey</param-name>
    <param-value>assist.context</param-value>
</context-param>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>


<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

My servlet code:

package com.a1s.assist.web.broadcast.controller;

/**
 * @author Alexey Belov
 */

import com.a1s.assist.broadcast.manager.BroadcastZoneManager;
import com.a1s.assist.broadcast.obj.BroadcastZone;
import com.a1s.assist.web.settings.controller.BaseSpringController;
import com.a1s.assist.web.settings.util.Messages;
import com.a1s.util.misc.ExceptionUtil;
import com.a1s.web.action.BaseAction;
import com.a1s.web.controller.FrontJsonController;
import org.jboss.logging.Logger;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@Lazy
@Controller
@RequestMapping(method = {RequestMethod.POST}, value = "/broadcast/zone")
public class BroadcastZoneController extends BaseSpringController {


    private Logger log = Logger.getLogger(BroadcastZoneController.class);
    @Autowired
    private BroadcastZoneManager broadcastZoneManager;

    @ResponseBody
    @RequestMapping(value = "/list")
    public void list(HttpServletRequest request,
                     HttpServletResponse response
    ) throws IOException {
        final ServletOutputStream out = response.getOutputStream();
        try {
            log.info("list zones");
            final JSONObject requestJson = (JSONObject) request.getAttribute(FrontJsonController.REQUEST_JSON_PARAMETER);
            final JSONObject parseJson = requestJson.getJSONObject("request").getJSONObject("params").getJSONObject(BroadcastZone.WRAP);
            final String operatorId = parseJson.getString("operatorId");
            final String parentId = parseJson.getString("parentId");
            final List<BroadcastZone> all = broadcastZoneManager.listChildsTree(parentId, operatorId);
            final List list = BaseAction.toJson(all);
            BaseAction.sendJsonOk(out, list);
        } catch (Exception e) {
            log.error(e);
            BaseAction.sendJsonError(out, Messages.IO_ERROR, "Unknown error: " + ExceptionUtil.getStackTrace(e), new JSONObject());
        }
    }
}

So when i try to start wildfly without module which contains BroadcastZone, i get exception:

Failed to start service jboss.undertow.deployment.default-server.default-host./ROOT: org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./ROOT: Failed to start service
        at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1904) [jboss-msc-1.2.2.Final.jar:1.2.2.Final]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [rt.jar:1.8.0_05]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [rt.jar:1.8.0_05]
        at java.lang.Thread.run(Thread.java:745) [rt.jar:1.8.0_05]
Caused by: java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0': Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: com/a1s/assist/broadcast/obj/BroadcastZone
        at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:222)
        at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:87)
        at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.start(UndertowDeploymentService.java:72)
        at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1948) [jboss-msc-1.2.2.Final.jar:1.2.2.Final]
        at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1881) [jboss-msc-1.2.2.Final.jar:1.2.2.Final]
        ... 3 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0': Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: com/a1s/assist/broadcast/obj/BroadcastZone
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
        at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:173)
        at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:193)
        ... 7 more
Caused by: java.lang.NoClassDefFoundError: com/a1s/assist/broadcast/obj/BroadcastZone
        at java.lang.Class.getDeclaredMethods0(Native Method) [rt.jar:1.8.0_05]
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2688) [rt.jar:1.8.0_05]
        at java.lang.Class.getDeclaredMethods(Class.java:1962) [rt.jar:1.8.0_05]
        at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:571)
        at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:488)
        at org.springframework.web.method.HandlerMethodSelector.selectMethods(HandlerMethodSelector.java:57)
        at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:169)
        at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:144)
        at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:123)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:126)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
        ... 21 more
Caused by: java.lang.ClassNotFoundException: com.a1s.assist.broadcast.obj.BroadcastZone from [Module "deployment.ROOT.war:main" from Service Module Loader]
        at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:213)
        at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:459)
        at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:408)
        at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:389)
        at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:134)
        ... 33 more

What can i do to make spring load controllers only when request is posting on my mapping. And NoClassDefFound error should raise only then, but not during startup?

I finally realized why that error happenned. The thing is in load-on-startup element. I thought it will not load on startup when the value is zero. Today i figured out, that:

The load-on-startup element indicates that this servlet should be loaded (instantiated and have its init() called) on the startup of the web application. The optional contents of these element must be an integer indicating the order in which the servlet should be loaded. If the value is a negative integer, or the element is not present, the container is free to load the servlet whenever it chooses. If the value is a positive integer or 0, the container must load and initialize the servlet as the application is deployed. The container must guarantee that servlets marked with lower integers are loaded before servlets marked with higher integers. The container may choose the order of loading of servlets with the same load-on-start-up value.

That is why i got NoClassDefFound on startup.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM