foxinmy / weixin4j

(微信开发工具包)weixin sdk for Java

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

在spring-mvc中通过线程调用方式使用weixin4j-server时,netty线程服务关闭异常

HelloSetsuna opened this issue · comments

测试环境版本如下:

    <properties>
        <java-version>1.8</java-version>
        <springframework-version>4.3.8.RELEASE</springframework-version>
        <version-wechat4j>1.7.6</version-wechat4j>
        <version-wechat4j-server>1.1.8</version-wechat4j-server>
    </properties>

我按照你给的例子编写的自己的Thread实现

import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.handler.DebugMessageHandler;
import com.foxinmy.weixin4j.spring.SpringBeanFactory;
import com.foxinmy.weixin4j.startup.WeixinServerBootstrap;
import com.foxinmy.weixin4j.util.AesToken;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 微信消息处理Netty服务配置
 * Created by hello on 2017/6/22.
 */
@Component
public class WechatServerThread implements ApplicationContextAware {

    private Logger logger = LogManager.getLogger(getClass());

    /**
     * 服务监听的端口号,目前微信只支持80端口,可以考虑用nginx做转发到此端口
     */
    private int port;
    /**
     * 服务器token信息
     * 明文模式:String aesToken = ""; 密文模式:AesToken aesToken = new
     * AesToken("公众号appid", "公众号token","公众号加密/解密消息的密钥");
     */
    private AesToken aesToken;

    /**
     * 处理微信消息的全限包名(也可通过addHandler方式一个一个添加)
     */
    private String handlerPackage="veda.oems.service.wechat.handler";

    /**
     * 用spring去获取bean
     */
    private ApplicationContext applicationContext;

    public WechatServerThread(){}

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Environment environment = applicationContext.getEnvironment();
        this.applicationContext = applicationContext;
        // 设置
        String runModel = environment.getRequiredProperty("system.run.model");
        logger.info("wechat server in "+runModel+" environment");
        switch (runModel){
            case "develop":
                this.port = environment.getRequiredProperty("weixin4j.server.port", int.class);
                this.aesToken = new AesToken(
                        environment.getRequiredProperty("weixin4j.server.app.id", String.class),
                        environment.getRequiredProperty("weixin4j.server.app.token", String.class),
                        environment.getRequiredProperty("weixin4j.server.app.aeskey", String.class)
                );
                break;
            case "product":
                this.port = environment.getRequiredProperty("weixin4j.server.port", int.class);
                this.aesToken = new AesToken(
                        environment.getRequiredProperty("weixin4j.server.app.id", String.class),
                        environment.getRequiredProperty("weixin4j.server.app.token", String.class),
                        environment.getRequiredProperty("weixin4j.server.app.aeskey", String.class)
                );
            default:
                logger.info("<*> can not found the run model");
        }
        this.start();
    }

    private ExecutorService executor;

    /**
     * 启动函数
     */
    public void start() {
        executor = Executors.newCachedThreadPool();
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    logger.info("wechat message netty server start success");
                    new WeixinServerBootstrap(aesToken) // 指定开发者token信息。
                            .handlerPackagesToScan(handlerPackage) // 扫描处理消息的包。
                            .resolveBeanFactory(
                                    new SpringBeanFactory(applicationContext)) // 声明处理消息类由Spring容器去实例化。
                            .addHandler(DebugMessageHandler.global) // 当没有匹配到消息处理时输出调试信息,开发环境打开。
                            .openAlwaysResponse() // 当没有匹配到消息处理时输出空白回复(公众号不会出现「该公众号无法提供服务的提示」),正式环境打开。
                            .startup(port); // 绑定服务的端口号,即对外暴露(微信服务器URL地址)的服务端口。
                } catch (WeixinException e) {
                    InternalLoggerFactory.getInstance(getClass()).error( "wechat message netty server run error ", e);
                }
            }
        });
    }

    @PreDestroy
    public void stop() {
        //executor.shutdownNow();
        executor.shutdown();
        logger.info("wechat message netty server stop success");
    }
}

我现在只是在测试,未正常投入生产使用(没有写任何的Handler),使用的那几个配置项都是我伪造的,测试时启动正常,但是我在IDEA里将Tomcat停止或重启的时候,虽然没有报任何的异常,但是会一直处在未关闭完成的状态,我将原本的 executor.shutdown(); 换成 executor.shutdownNow(); 后可以正常关闭,但是在关闭后会报一些异常,下面我将相关异常列出来:

"C:\Program Files\Apache Software Foundation\Tomcat 8.5\bin\catalina.bat" stop
Using CATALINA_BASE:   "C:\Users\xxx\.IntelliJIdea2017.1\system\tomcat\Unnamed_oems_2"
Using CATALINA_HOME:   "C:\Program Files\Apache Software Foundation\Tomcat 8.5"
Using CATALINA_TMPDIR: "C:\Program Files\Apache Software Foundation\Tomcat 8.5\temp"
Using JRE_HOME:        "C:\Program Files\Java\jdk1.8.0_121"
Using CLASSPATH:       "C:\Program Files\Apache Software Foundation\Tomcat 8.5\bin\bootstrap.jar;C:\Program Files\Apache Software Foundation\Tomcat 8.5\bin\tomcat-juli.jar"
22-Jun-2017 19:41:39.431 信息 [main] org.apache.catalina.core.StandardServer.await A valid shutdown command was received via the shutdown port. Stopping the Server instance.
22-Jun-2017 19:41:39.432 信息 [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
22-Jun-2017 19:41:39.512 信息 [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["ajp-nio-8009"]
22-Jun-2017 19:41:39.585 信息 [main] org.apache.catalina.core.StandardService.stopInternal Stopping service Catalina
22-Jun-2017 19:41:39.592 信息 [localhost-startStop-2] org.springframework.context.support.AbstractApplicationContext.doClose Closing WebApplicationContext for namespace 'dispatcher-servlet': startup date [Thu Jun 22 19:41:11 CST 2017]; parent: Root WebApplicationContext
22-Jun-2017 19:41:39.593 信息 [localhost-startStop-2] org.springframework.context.support.AbstractApplicationContext.doClose Closing Root WebApplicationContext: startup date [Thu Jun 22 19:41:09 CST 2017]; root of context hierarchy
Exception in thread "pool-2-thread-1" [19:41:39:594] [INFO] - veda.oems.config.wechat.WechatServerThread.stop(WechatServerThread.java:112) - wechat message netty server stop success
java.lang.NoSuchMethodError: com.foxinmy.weixin4j.exception.WeixinException.<init>(Ljava/lang/String;Ljava/lang/Exception;)V
	at com.foxinmy.weixin4j.startup.WeixinServerBootstrap.startup(WeixinServerBootstrap.java:208)
	at com.foxinmy.weixin4j.startup.WeixinServerBootstrap.startup(WeixinServerBootstrap.java:170)
	at veda.oems.config.wechat.WechatServerThread$1.run(WechatServerThread.java:100)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
22-Jun-2017 19:41:39.617 警告 [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [oems] registered the JDBC driver [com.mysql.cj.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
22-Jun-2017 19:41:39.626 信息 [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
22-Jun-2017 19:41:39.627 信息 [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["ajp-nio-8009"]
22-Jun-2017 19:41:39.627 信息 [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
22-Jun-2017 19:41:39.628 信息 [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["ajp-nio-8009"]
22-Jun-2017 19:41:41.698 信息 [nioEventLoopGroup-2-1] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [io.netty.util.concurrent.DefaultPromise$2]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
 java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [io.netty.util.concurrent.DefaultPromise$2]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
	at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1305)
	at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1293)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1158)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)

Exception in thread "nioEventLoopGroup-2-1" java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassNotFoundException: Illegal access: this web application instance has been stopped already. Could not load [io.netty.util.concurrent.DefaultPromise$2]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
	at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1295)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1158)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	... 5 more
Caused by: java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [io.netty.util.concurrent.DefaultPromise$2]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
	at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1305)
	at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1293)
	... 7 more
Exception in thread "nioEventLoopGroup-2-2" java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "nioEventLoopGroup-3-14" Exception in thread "nioEventLoopGroup-3-15" Exception in thread "nioEventLoopGroup-2-3" Exception in thread "nioEventLoopGroup-3-11" Exception in thread "nioEventLoopGroup-3-1" Exception in thread "nioEventLoopGroup-3-16" Exception in thread "nioEventLoopGroup-3-13" Exception in thread "nioEventLoopGroup-2-4" java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
Exception in thread "nioEventLoopGroup-3-12" 	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "nioEventLoopGroup-3-8" java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
Exception in thread "nioEventLoopGroup-3-9" Exception in thread "nioEventLoopGroup-3-7" Exception in thread "nioEventLoopGroup-3-3" Exception in thread "nioEventLoopGroup-3-5" Exception in thread "nioEventLoopGroup-3-4" Exception in thread "nioEventLoopGroup-3-10" Exception in thread "nioEventLoopGroup-3-6" Exception in thread "nioEventLoopGroup-3-2" 	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:589)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:397)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:155)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)
Disconnected from server

在我使用 executor.shutdown(); 关闭,Tomcat处于未关闭完成的状态时对netty服务发了一次请求,也会出异常,我不知道netty关闭需要多久时间,我等了好一会也没见Tomcat完全停止,异常如下:

"C:\Program Files\Apache Software Foundation\Tomcat 8.5\bin\catalina.bat" stop
Using CATALINA_BASE:   "C:\Users\xxx\.IntelliJIdea2017.1\system\tomcat\Unnamed_oems_2"
Using CATALINA_HOME:   "C:\Program Files\Apache Software Foundation\Tomcat 8.5"
Using CATALINA_TMPDIR: "C:\Program Files\Apache Software Foundation\Tomcat 8.5\temp"
Using JRE_HOME:        "C:\Program Files\Java\jdk1.8.0_121"
Using CLASSPATH:       "C:\Program Files\Apache Software Foundation\Tomcat 8.5\bin\bootstrap.jar;C:\Program Files\Apache Software Foundation\Tomcat 8.5\bin\tomcat-juli.jar"
22-Jun-2017 19:54:50.257 信息 [main] org.apache.catalina.core.StandardServer.await A valid shutdown command was received via the shutdown port. Stopping the Server instance.
22-Jun-2017 19:54:50.258 信息 [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
22-Jun-2017 19:54:50.336 信息 [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["ajp-nio-8009"]
22-Jun-2017 19:54:50.410 信息 [main] org.apache.catalina.core.StandardService.stopInternal Stopping service Catalina
22-Jun-2017 19:54:50.415 信息 [localhost-startStop-2] org.springframework.context.support.AbstractApplicationContext.doClose Closing WebApplicationContext for namespace 'dispatcher-servlet': startup date [Thu Jun 22 19:54:23 CST 2017]; parent: Root WebApplicationContext
22-Jun-2017 19:54:50.417 信息 [localhost-startStop-2] org.springframework.context.support.AbstractApplicationContext.doClose Closing Root WebApplicationContext: startup date [Thu Jun 22 19:54:21 CST 2017]; root of context hierarchy
[19:54:50:418] [INFO] - veda.oems.config.wechat.WechatServerThread.stop(WechatServerThread.java:112) - wechat message netty server stop success
22-Jun-2017 19:54:50.437 警告 [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [oems] registered the JDBC driver [com.mysql.cj.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
22-Jun-2017 19:54:50.439 严重 [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [oems] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@5eecc734]) and a value of type [io.netty.util.internal.InternalThreadLocalMap] (value [io.netty.util.internal.InternalThreadLocalMap@3c48085b]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
22-Jun-2017 19:54:50.446 信息 [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
22-Jun-2017 19:54:50.447 信息 [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["ajp-nio-8009"]
22-Jun-2017 19:54:50.447 信息 [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
22-Jun-2017 19:54:50.448 信息 [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["ajp-nio-8009"]
22-Jun-2017 19:55:10.542 信息 [nioEventLoopGroup-2-1] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [io.netty.channel.socket.nio.NioSocketChannel]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
 java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [io.netty.channel.socket.nio.NioSocketChannel]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
	at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1305)
	at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1293)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1158)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	at io.netty.channel.socket.nio.NioServerSocketChannel.doReadMessages(NioServerSocketChannel.java:139)
	at io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:68)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)

22-Jun-2017 19:55:10.543 信息 [nioEventLoopGroup-2-1] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [java.nio.channels.SocketChannel]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
 java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [java.nio.channels.SocketChannel]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
	at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1305)
	at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1293)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1158)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
	at io.netty.channel.socket.nio.NioServerSocketChannel.doReadMessages(NioServerSocketChannel.java:146)
	at io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:68)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
	at java.lang.Thread.run(Thread.java:745)

目前我打算先直接try catch掉,找了许久的wechat的Java的SDK,就你这更新的比较勤,打算用下试试,加油哦

commented

感谢关注。

我这边也重现,暂时没有头绪,不过在WeixinServerBootstrap类新增了shutdown方法

我再调试一下吧。:)

目前做的一个类似项目因存在写异步日志的线程一直存活,使用tomcat的关闭命令stop.sh是关闭不了tomcat的,只能使用kill强杀,看上去你这个是由于线程池中的线程还在运行,你使用executor.shutdownNow()强杀所有线程,netty服务监听到无服务导致抛出的异常吧。

commented

@michjony 你好,应该是你说得这样,但是我在服务启动类WeixinServerBootstrap 中加了netty的shutdown方法,然后在自己的线程中的stop方法中调用也会抛出上述java.lang.NoClassDefFoundError: io/netty/util/concurrent/DefaultPromise$2异常,netty启动的线程可以正常停止。

public boolean shutdown() {
        if (bootstrap == null) {
            return false;
        }
        ServerBootstrapConfig c = bootstrap.config();
        c.group().shutdownGracefully();
        c.childGroup().shutdownGracefully();
        messageHandlerList = null;
        messageInterceptorList = null;
        messageDispatcher = null;
        bootstrap = null;
        return true;
    }

初步怀疑是tomcat的ClassLoader的原因,但不知道从何处着手。

commented

似乎解决了。

首先需要在web.xml配置一个listener

	<listener>
		<listener-class>com.foxinmy.weixin4j.example.server.Weixin4jServerStartupListener</listener-class>
	</listener>

listener实现ServletContextListener接口:

public class Weixin4jServerStartupListener implements ServletContextListener {
    /**
     * 服务监听的端口号,目前微信只支持80端口,可以考虑用nginx做转发到此端口
     */
    private final int port;
    /**
     * 服务器token信息
     */
    /**
     * 明文模式:String aesToken = ""; 密文模式:AesToken aesToken = new
     * AesToken("公众号appid", "公众号token","公众号加密/解密消息的密钥");
     */
    private final AesToken aesToken;
    /**
     * 处理微信消息的全限包名(也可通过addHandler方式一个一个添加)
     */
    private final String handlerPackage;

    public Weixin4jServerStartupListener() {
        // 可以考虑通过参数获取
        this.port = 30000;
        this.aesToken = new AesToken("weixin4j");
        this.handlerPackage = "com.foxinmy.weixin4j.example.server.handler";
    }

    private WeixinServerBootstrap bootstrap;

    /**
     * 启动服务
     *
     * @param applicationContext
     */
    public void start(final ApplicationContext applicationContext) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                bootstrap = new WeixinServerBootstrap(aesToken) // 指定开发者token信息。
                        .handlerPackagesToScan(handlerPackage) // 扫描处理消息的包。
                        .resolveBeanFactory(new SpringBeanFactory(applicationContext)) // 声明处理消息类由Spring容器去实例化。
                        .addHandler(DebugMessageHandler.global) // 当没有匹配到消息处理时输出调试信息,开发环境打开。
                        .openAlwaysResponse(); // 当没有匹配到消息处理时输出空白回复(公众号不会出现「该公众号无法提供服务的提示」),正式环境打开。
                bootstrap.startup(port); // 绑定服务的端口号,即对外暴露(微信服务器URL地址)的服务端口。
            }
        }).start();
    }

    /**
     * 关闭服务
     */
    public void stop() {
        bootstrap.shutdown(true);
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        start(WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()));
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        stop();
    }
}

WeixinServerBootstrap关闭服务shutdown方法如下:

 /**
     * 关闭微信服务
     *
     * @param blocking
     *            阻塞关闭
     * @return
     */
    public boolean shutdown(boolean blocking) {
        if (bootstrap == null) {
            return false;
        }
        ServerBootstrapConfig c = bootstrap.config();
        Future<?> bossF = c.group().shutdownGracefully();
        Future<?> workerF = c.childGroup().shutdownGracefully();
        if (blocking) {
            bossF.awaitUninterruptibly();
            workerF.awaitUninterruptibly();
        }
        messageHandlerList = null;
        messageInterceptorList = null;
        messageDispatcher = null;
        bootstrap = null;
        return true;
    }

我看看能不能在weixin4j-server包里写一个通用的listener

感谢反馈。

嗯,有空我再测试下