eclipse使用Gradle启动成功,打成war包用Tomcat启动报BeanCreationException

问题描述

使用netty-socket构建websocket,初始化NettySocketioService时报错,但是使用eclipse中的gradle启动没有问题.

不清楚是是什么原因,报错提示是找不到netty的一个方法,但是我本地引了包,解压的war包里面也找到了netty的这个jar和其中的方法。

本项目没有在其他地方引用netty的jar,这几个netty的jar也是引用了netty-socketio后,由它依赖下载的,不存在冲突


问题出现的环境背景及自己尝试过哪些方法

java1.8,tomcat8.5.12,netty-socketio:1.7.17

尝试过将init方法用@PostConstruct启动,无效。


相关代码

applicationContext-socket.xml

<bean id="socketIO" class="com.excenon.community.socket.config.NettySocketioService" init-method="init"></bean>

NettySocketioService.java
`public class NettySocketioService {

private static final Logger logger = LoggerFactory.getLogger(NettySocketioService.class);

private Cache<String, Object> socketCache = GCacheGenerator.generator(10, 5, 1, TimeUnit.DAYS);

private SocketIOServer server;

@Autowired
private RedisHelper redisHelper;

public void init() {
    // ZlibCodecFactory.isSupportingWindowSizeAndMemLevel();

    logger.info("Socket_IO开始初始化");
    Configuration configuration = new Configuration();
    configuration.setHostname("10.3.30.182");
    configuration.setPort(9009);

    server = new SocketIOServer(configuration);
    server.addConnectListener(new ConnectListener() {

        @Override
        public void onConnect(SocketIOClient client) {
            String uuid = client.getSessionId().toString();
            if (StringUtils.isBlank(uuid)) {
                logger.info("异常,socket请求sessionId为空");
                client.sendEvent("error", "异常,socket请求sessionId为空");
                client.disconnect();
            }

            // 获取Redis中的token信息
            String token = client.getHandshakeData().getSingleUrlParam("mac");
            byte[] userB = redisHelper.hget((SystemConstant.SPRING_SESSION_PREFIX + token).getBytes(),
                "sessionAttr:sysUser".getBytes());
            if (userB == null) {
                logger.info("未找到用户登录信息, uuid : {}, userToken : {}", uuid, token);
                client.sendEvent("error", "未找到用户登录信息");
                client.disconnect();
            }
            // 反序列化user信息
            ByteArrayInputStream bais = new ByteArrayInputStream(userB);
            ObjectInputStream ois = null;
            SysUser user = null;
            try {
                ois = new ObjectInputStream(bais);
                user = (SysUser)ois.readObject();
            } catch (Exception e) {
                logger.error("用户信息反序列化失败, uuid : {}, userToken : {}", uuid, token);
                client.sendEvent("error", "用户信息反序列化失败");
                client.disconnect();
            }

            addCache(uuid, user);
            logger.info("客户端: {}已连接,mac={}, user:{}, user:{}, userid:{}", client.getSessionId(), token, user,
                userB.toString(), user.getId());
        }
    });

    server.addDisconnectListener(new DisconnectListener() {

        @SuppressWarnings("unchecked")
        @Override
        public void onDisconnect(SocketIOClient client) {
            // 链接disconnect,销毁该链接uuid和userid的关联
            String uuid = client.getSessionId().toString();
            if (StringUtils.isNotBlank(uuid)) {
                String userId = (String)socketCache.getIfPresent(uuid);
                if (StringUtils.isNotBlank(userId)) {
                    socketCache.invalidate(uuid);
                    List<String> uuids = (List<String>)socketCache.getIfPresent(userId);
                    if (CollectionUtils.isNotEmpty(uuids) && uuids.contains(uuid)) {
                        uuids.remove(uuid);
                        if (CollectionUtils.isEmpty(uuids)) {
                            socketCache.invalidate(userId);
                        } else {
                            socketCache.put(userId, uuids);
                        }
                    }
                }
            }
        }
    });
    server.start();
    logger.info("Socket_IO已启动");
}`

}

启动报错

报错.png

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'socketIO' defined in URL [file:/D:/apache-tomcat-8.0.52/webapps/cmty_socket/WEB-INF/classes/applicationContext-socket.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: io.netty.handler.codec.compression.ZlibCodecFactory.isSupportingWindowSizeAndMemLevel()Z
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566)
        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:302)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:762)
        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 org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4900)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5363)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:755)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:731)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
        at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:973)
        at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1850)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoSuchMethodError: io.netty.handler.codec.compression.ZlibCodecFactory.isSupportingWindowSizeAndMemLevel()Z
        at com.excenon.community.socket.config.NettySocketioService.init(NettySocketioService.java:45)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1694)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562)
        ... 25 more
阅读 3k
2 个回答

最后的解决方案记录一下:
1、为netty-socket单独用一个线程启动(加锁保证唯一),在v2ex上看到一种说法,就是netty好像会在某些情况下阻塞spring的加载
2、检查gradle依赖,发现有一个netty-all的包,虽然不是netty-socket依赖的,是由rocketMQ依赖,但是它的版本过低也会导致启动失败,最后在配置中指定了netty-all引用最新的版本

java.lang.NoSuchMethodError: io.netty.handler.codec.compression.ZlibCodecFactory.isSupportingWindowSizeAndMemLevel()Z

目测是版本问题, 试试netty 4.1或类似的

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题