Illegal Access Exception After Web Application Instance Stops: Analysis of Thread Management and ClassLoader Lifecycle

Dec 04, 2025 · Programming · 11 views · 7.8

Keywords: Java | Tomcat | ClassLoader | Thread Management | Hot Deployment

Abstract: This paper provides an in-depth analysis of the "Illegal access: this web application instance has been stopped already" exception in Java web applications. Through a concrete case study of Spring Bean thread management, it explores the interaction between class loader lifecycle and background threads in Tomcat containers. The article first reproduces the exception scenario, then analyzes it from technical perspectives including class loader isolation mechanisms and the impact of hot deployment on runtime environments, and finally presents two solutions based on container restart and thread pool management, comparing their applicable scenarios.

Exception Scenario Reproduction and Technical Background

In Java web application development based on Tomcat, developers frequently encounter mismatches between background thread management and container lifecycle management. A typical scenario involves defining a Bean in Spring configuration that starts background threads via init-method to perform periodic tasks such as email checking. When the application is deployed or redeployed, a java.lang.IllegalStateException may occur with the error message "Illegal access: this web application instance has been stopped already".

Consider the following configuration example:

<bean id="appStarter" class="com.myapp.myClass" init-method="init" destroy-method="destroy"/>

The corresponding Java class implementation:

public class myClass {
    private Thread t;
    
    public void init() {
        t = new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        doStuff();
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t.start();
    }
    
    public void destroy() {
        t.interrupt();
    }
    
    public void doStuff() {
        Session session = Session.getDefaultInstance(System.getProperties(), null);
        Store store = session.getStore("imap");
        store.connect(hostName, userName, password);
        // Additional email processing logic
    }
}

In-depth Analysis of Exception Causes

The core cause of this exception lies in the desynchronization between Tomcat's class loader isolation mechanism and thread lifecycle. Tomcat creates independent WebappClassLoader instances for each web application. When an application is stopped or redeployed, this ClassLoader is marked as invalid. Any attempt to load new classes through this ClassLoader at that point will throw an IllegalStateException.

In the example code, the doStuff() method internally calls Session.getStore("imap"), which triggers dynamic loading of the com.sun.mail.imap.IMAPStore class. If the web application instance has already stopped (e.g., during hot deployment) while the background thread is still running, an illegal access exception occurs.

The exception stack trace clearly illustrates this process:

java.lang.IllegalStateException
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1273)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1233)
    at javax.mail.Session.getService(Session.java:755)
    // Subsequent stack trace omitted

Solution Comparison and Implementation

Solution 1: Container Restart (Temporary Solution)

As indicated in the best answer, restarting the Tomcat server can immediately resolve the issue. This is because restarting completely clears all ClassLoader instances and thread states, ensuring the application starts from a clean environment. This approach is suitable for the following scenarios:

However, the restart solution has significant limitations: it cannot prevent the problem from recurring in hot deployment scenarios, and frequent restarts in production environments affect service availability.

Solution 2: Thread Pool Management and Lifecycle Synchronization (Fundamental Solution)

A more thorough solution involves using container-managed thread executor services to ensure thread lifecycle synchronization with web application lifecycle. In Java EE environments, ManagedExecutorService can be utilized:

@Resource
private ManagedExecutorService executor;

public void init() {
    executor.submit(() -> {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                doStuff();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            } catch (Exception e) {
                // Exception handling logic
            }
        }
    });
}

public void destroy() {
    // ManagedExecutorService automatically manages thread termination
}

The advantages of this approach include:

For non-Java EE environments, consider using third-party library mechanisms like Apache Commons Pool's EvictorThread, or implement custom thread management strategies to ensure proper termination of all background threads when the application stops.

Best Practice Recommendations

Based on the above analysis, the following practical recommendations are proposed:

  1. Thread Creation Timing: Avoid creating infinite loop threads directly in Bean initialization methods. Consider using more controllable asynchronous mechanisms such as scheduled tasks or message queues.
  2. Resource Cleanup: Ensure all destroy methods properly release resources and terminate threads, using Thread.interrupt() in conjunction with interrupt status checks.
  3. Class Loader Isolation: Understand Tomcat's class loader hierarchy to avoid accessing classes loaded by WebappClassLoader after application stoppage.
  4. Monitoring and Logging: Add appropriate logging to monitor background thread status and promptly detect lifecycle mismatches.

By properly designing thread management strategies and ensuring synchronization with container lifecycle, "Illegal access" exceptions can be effectively prevented, improving the stability and maintainability of web applications.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.