非法访问:此Web应用程序实例已停止

二月 08, 2021 5:48:11 下午 org.apache.catalina.loader.WebappClassLoaderBase checkStateForResourceLoading
信息: 非法访问:此Web应用程序实例已停止。无法加载[com.watermelon.acs.grpc.task.GatewayUpdateTask]。为了调试以及终止导致非法访问的线程,将抛出以下堆栈跟踪。
java.lang.IllegalStateException: 非法访问:此Web应用程序实例已停止。无法加载[com.wm.acs.grpc.task.GatewayUpdateTask]。为了调试以及终止导致非法访问的线程,将抛出以下堆栈跟踪。
        at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1385)
        at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1373)
        at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1226)
        at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1188)
        at ch.qos.logback.classic.spi.PackagingDataCalculator.loadClass(PackagingDataCalculator.java:204)
        at ch.qos.logback.classic.spi.PackagingDataCalculator.bestEffortLoadClass(PackagingDataCalculator.java:228)
        at ch.qos.logback.classic.spi.PackagingDataCalculator.computeBySTEP(PackagingDataCalculator.java:135)
^C      at ch.qos.logback.classic.spi.PackagingDataCalculator.populateUncommonFrames(PackagingDataCalculator.java:111)
        at ch.qos.logback.classic.spi.PackagingDataCalculator.populateFrames(PackagingDataCalculator.java:104)
        at ch.qos.logback.classic.spi.PackagingDataCalculator.calculate(PackagingDataCalculator.java:58)
        at ch.qos.logback.classic.spi.ThrowableProxy.calculatePackagingData(ThrowableProxy.java:142)
        at ch.qos.logback.classic.spi.LoggingEvent.<init>(LoggingEvent.java:122)
        at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:419)
        at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
        at ch.qos.logback.classic.Logge

今天遇到一个很奇怪的问题,记录一下
环境 centos + tomcat + springboot

项目发布到centos后,有概率会输出以上提到的log,输出非常快,很短时间的log大小就达到几十G,而且关闭tomcat后,log仍在输出,重启centos后就好了,但是项目启动后,间隔不了多久,又会出这样的问题。在网上搜了一下,说是context.xml里,把reloadable改为false,但是改完后,问题没有解决,反而觉得问题的出现概率更高了。
后来仔细看log,里面提到了自己写的代码,GatewayUpdateTask,问题很可能和这个代码有关,因为之前并没有这个问题。

GatewayUpdateTask是一个线程,派生自Runable,里面的大体代码如下:

@Override
public void run() {
    while (true)
        try {
            doStuff();
            Thread.sleep(10000);
        } catch (Exception e) {
            e.printStackTrace();
        }
}

这是一个自定义的线程
然后通过关键字又搜索到了如下链接
https://stackoverflow.com/questions/4945153/illegal-access-this-web-application-instance-has-been-stopped-already

看了这个文章后豁然开朗,大体是说springboot中不要使用自定义的线程,而是用托管的线程池。
然后尝试着把run函数改为如下:

@Override
public void run() {
    //while (true)
        try {
            doStuff();
            Thread.sleep(10000);
        } catch (Exception e) {
            e.printStackTrace();
        }
}

再发布,问题果然解决了

后来想想,线程里就是定期执行一个处理,于是采用springboot定时器的方式来处理,如下:

@Override
@Component
@EnableScheduling
public class GatewayUpdateService {

    @Autowired
    ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    GatewayUpdateTask gatewayUpdateTask;

    Logger logger = LoggerFactory.getLogger(this.getClass());

    //@PostConstruct
    @Scheduled(fixedRate=10000)
    public void onTimer() {
        logger.info("onTimer 刷新网关列表");
        threadPoolTaskExecutor.submit(new Thread(gatewayUpdateTask));
    }

    @PreDestroy
    public void destroy() {
        threadPoolTaskExecutor.shutdown();
    }
}

也就是说,线程不再循环,而是每间隔10秒,执行一遍任务,执行完成后,线程退出,再次发布,问题解决。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐