preface

In Java applications, common Web servers include Tomcat, WebLogic, Jetty, and Undertwo. However, according to the Java 2019 and 2020 Ecological Usage reports, Tomcat has a much larger number of users, which is also due to its open source and free nature.

Java Ecosphere Usage Report 2019 2020 Java Ecosystem Report From the perspective of software architecture development, software architecture generally goes through the following stages:From a Java Web perspective, the architecture roughly goes through:From the perspective of the current architecture used by enterprises, there are a lot of projects using SSM architecture, SSH is basically obsolete (mostly old project maintenance), and a large number of enterprises are moving to microservices architecture.

In terms of the Spring ecosystem, most small and medium businesses use SpringBoot, which itself integrates Tomcat, Jetty, and Undertwo containers, so why do we need to spend time on Tomcat?

  1. At present, Tomcat is still the mainstream Java Web container.
  2. In Java Web project tuning, such as SSM projects, the JVM and Tomcat are equally important and both need to be optimized.
  3. Although Springboot has built-in Tomcat container and configured default Tomcat parameters, when the default tomcat parameters cannot meet the optimization requirements of the project, it is necessary for the optimizer to manually optimize related parameters, so it is very necessary to study Tomcat.
  4. Familiarity with tomcat architecture is the foundation and prerequisite for project optimization in the future.

Tomcat Architecture Description

Knowledge:

  1. Tomcat directory Structure
  2. Brief Architecture of Tomcat
  3. Tomcat components and their relationships
  4. Tomcat server. XML configuration details
  5. Tomcat Startup Parameters (Startup Script)

Tomcat

Is a Java-based WEB container, which implements JAVA EE Servlet and JSP specifications, and is different from Nginx Apache server is generally used for dynamic request processing. In architecture design, component – oriented approach is adopted. That is, the overall function is assembled through the way of components. In addition, each component can be replaced to ensure flexibility.

According to the Official Tomcat, it has been updated to Tomcat 10, but currently most enterprises are using Tomcat version 8 or 9.

Tomcat directory Structure

  • Bin: executable file. The. Sh file ends in Linux executable file. The. Bat file ends in Windows executable file
  • Conf: indicates the configuration file
  • Lib: Jar package related to Tomcat
  • Temp: indicates a temporary file
  • Webapps: Store projects
  • Work: indicates the working directory

Bin directory

The bin directory stores executable files and briefly ends common commandsThe following general commands are mainly explained here. Other commands are not described in detail

  • Catalina. sh actually starts the Tomcat file, where you can set JVM parameters
  • Startup. sh Program project command file
  • Version. sh Displays tomcat version information
  • Sh Shuts down the program

The conf directory

Conf folder is used to store Tomcat configuration files

1.catalina.policy

Project security files to prevent spoofs or JSPS from executing destructive code with commands like system.exit (0) that might affect the container. This file is only used when Tomcat is started with the -security command line argument, that is, when Tomcat is started,startup.sh  -security 。

In the figure above, two projects, project 1 and Project 2, are deployed under the Tomcat container. Since there is code system.exit (0) in project 1, when accessed, this code causes the entire Tomcat to stop and therefore project 2 to stop.

To solve the problem that the Tomcat container is damaged due to spoofs or unsafe codes in project 1, and thus affects the normal operation of other projects, add the -security parameter when starting Tomcat container, that is, startup.sh -security. So even if there is system.exit (0) in project 1, it will only stop project 1 and not affect the Tomcat container, whereas the active configuration file is catalina.policy.

**2.catalina.properties **

Configure tomcat startup information files

**3.context.xml **

Monitors and loads resource files, and automatically loads when the monitored files change

4. Jaspic – will. XML and jaspic – will. XSD

These two files are not commonly used

5.logging.properties

This file is a Tomcat log file, including the configuration of the Tomcat output format and log level

6.server.xml

The Tomcat core architecture master file will be analyzed in detail below.

7. Tomcat – users. XML and tomcat – users. XSD

Tomcat user files, such as remote login accounts

Tomcat-users. XSD is a description and constraint file for tomcat-users. XML

8.web.xml

Tomcat global configuration file.

Lib directory

The lib folder is used to store Jar packages dependent on Tomcat. The following describes jar packages in the lib folder of Tomcat.Ecj-4.13.jar, which compiles.java to.class bytecode.

Suppose you want to compile mytest.java, then the JDK does two steps:

  • Step 1: Compile mytest.java to mytest.class

    javac  MyTest.java

  • Step 2: Execute mytest.class

    java MyTest.class

  • How about using ecJ-4.13.jar to execute mytest.java?

Java jar ecj – 4.13. Jar MyTest. Java

Logs directory

This folder represents Tomcat log files, which generally include the following six types of files:

catalina.date.log Indicates the Tomcat startup file
catalina.out Log indicates the log summary of catalina.date.log
host-manager.date.log Access host-manager project logs under Webapps, for example, IP address :8080/host-manager/ HTML
localhost.date.log This log records only Tomcat access logs, not service project logs
localhost_access_log.date.txt Said access tomcat all log records of the project, said the following access project localhost, host – manager. HTML, manager. HTML and test/index. The HTML logging four projects
manager.date.log Access manager project logs under Webapps, such as IP address :8080/manager/ HTML

Temp directory

Temp directory The user stores temporary files generated during tomcat running. (Clearing does not affect Tomcat operation).

Webapps directory

The Webapps directory is used to store applications. When Tomcat starts, the applications in the Webapps directory will be loaded. Applications can be distributed as folders, war packages, and JARS. Of course, you can also place the application anywhere on disk, as long as it is mapped in the configuration file.

The work directory

The work directory is used to store tomcat compiled files at runtime, such as JSP compiled files. To clear the cache, clear the work directory and restart Tomcat.

Brief Architecture of Tomcat

Tomcat components and their relationships

  • The Server and the Service
  • Connector Connector
    • The HTTP 1.1
    • SSL  https
    • Apache JServ Protocol (AJP) Apache private Protocol used for Tomcat, the Apache reverse proxy
  • Container
    • Catalina Engine Engine
    • Host The VM sends requests based on the domain name
    • Context isolates each WEB application and the ClassLoader of each Context is independent
  • Component
    • Manager
    • Logger (Log Management)
    • Loader
    • Pipeline (pipeline)
    • Valve (valve in pipe)

Tomcat server. XML configuration details

Basic configuration of the Server:

<Server> <Listener /><! --> <GlobaNamingResources> <! </GlobaNamingResources <Service> <! Service used to bind the Connector to the Engine --> <Connector8080/ > <! -- Connector --> <Connector8010/ > <! -- Connector --> <Connector8030/ > <! -- Connector --> <Engine> <! -- Execution engine --> <Logger /> <Realm /> <host"www.test.com" appBase=""> <! -- Virtual host --> <Logger /> <! -- Log configuration --> <Context"/applction" path=""/ > <! - context configuration - > < / host > < / Engine > < / Service > < / Server >Copy the code

server 

Root element: The top-level configuration of the server

Main attributes: port: indicates the port number of the shutdown command. Shutdown: indicates the shutdown command

  • Demonstrate the use of shutdown
Telent 127.0.0.1 8005 SHUTDOWNCopy the code

service

Service: You can configure multiple services by combining multiple connectors and an Engine into a single service.

Connector

Connector: Used to receive connections under a specified protocol and assign them to a unique Engine for processing.

Main attributes:

  • Protocol Protocol for listening. The default is HTTP /1.1

  • Port Specifies the port number to be created on the server

  • MinThread Number of threads created to process requests when the server is started

  • MaxThread Maximum number of threads that can be created to process requests

  • EnableLookups If it is true, the actual host name of the remote client can be queried by calling Request.getremoteHost (). If it is false, the IP address of the remote client is returned instead of queried

  • RedirectPort Specifies the port number that the server is redirecting after receiving an SSL transport request while processing an HTTP request

  • AcceptCount Specifies the number of requests that can be placed in the queue when all available threads for processing requests are used. Any requests exceeding this number will not be processed.

  • Address Binds a specific client address, 127.0.0.1

  • BufferSize bufferSize for each request bufferSize * maxThreads

  • Compression Whether to enable document compression

  • CompressionMinSize Specifies the minimum size of the document to be compressed

  • compressableMimeTypes    text/html,text/xml,text/plain

  • ConnectionTimeout Specifies the amount of time (in milliseconds) before the client initiates the link to the server to receive it.

  • ConnectionUploadTimeout Upload Connection timeout period

  • DisableUploadTimeout If true, connectionTimeout is used

  • KeepAliveTimeout Actively closes a long link when it is idle for a specified period of time, if the client requests this head”connection” “keep-alive”

  • MaxKeepAliveRequests Maximum number of ests The default value is 100

  • MaxSpareThreads BIO Maximum number of idle threads

  • Minimum number of idle threads in minSpareThreads BIO mode

  • SSLEnabled Specifies whether to enable SLL authentication. This function is required for Https access.

  • Demonstrates configuring multiple Connectors

 <Connector port="8860" protocol="org.apache.coyote.http11.Http11NioProtocol"
                connectionTimeout="20000"
                redirectPort="8862"
                URIEncoding="UTF-8"
                useBodyEncodingForURI="true"
                compression="on" compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/plain,text/javascript,text/css,application/x-json,application/json,application/x-javascript"
                maxThreads="1024" minSpareThreads="200"
                acceptCount="800"
                enableLookups="false"
        />
Copy the code

Engine

Engine: The actuator used to process connections. The default engine is Catalina. Only one Engine can be configured for a service.

Main attribute: name engine name defaultHost defaultHost

Host

Vm: Matches a VM based on the domain name. Similar to server in Nginx, the default virtual machine is localhost.

  • Demonstrates configuring multiple hosts
<Host name="www.test.com"  appBase="/usr/www/test"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"               prefix="www.luban.com.access_log" suffix=".txt"
               pattern="%h %l %u %t " %r" %s %b" />
</Host>
Copy the code

Context

Application Context: A host can be configured with multiple contexts, each with its own classPath. Isolate each other to avoid ClassPath conflicts.

  • Demonstrates configuring multiple contexts
<Context docBase="hello" path="/h" reloadable="true"/>
Copy the code

Valve

Valve: A filter that can be understood as request and is configured based on a subclass of the Valve interface. Here is a Valve that accesses logs.

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="www.luban.com.access_log" suffix=".txt" pattern="%h %l %u %t &quot; %r&quot; %s %b" />Copy the code

Tomcat startup parameters

How do we normally start Tomcat?

  1. Copy the WAR package to the Tomcat WebApp directory.
  2. Run the starut.bat script to start.
  3. The WAR package is automatically unpacked and loaded during startup.

But do we start a WEB project in Eclipse or IDEA by unpacking the War package into the Webapps directory as well? Obviously not. What it really does is create a deployment directory outside of the Tomcat program file, which is what you would do in a normal production environment: separate the Tomcat program directory from the deployment directory. All we need to do is specify CATALINA_HOME and CATALINA_BASE at startup.

Launch parameters description
JAVA_OPTS -xms100m -xmx200m -dfile. encoding=UTF-8
JAVA_HOME Specify the JDK directory, if not from Java environment variables.
CATALINA_HOME Tomcat program root directory
CATALINA_BASE The application deployment directory is $CATALINA_HOME by default
CATALINA_OUT Application log output directory: default $CATALINA_BASE/log
CATALINA_TMPDIR Application temporary directory: Default: $CATALINA_BASE/temp

You can write a script to implement the custom configuration:

Update startup script:

#! /bin/bashExport JAVA_OPTS=" -xms100m -XMx200m "export JAVA_HOME=/root/ SVR/JDK/export CATALINA_HOME=/root/ SVR /apache-tomcat-7.0.81  export CATALINA_BASE="`pwd`" case $1 in start) $CATALINA_HOME/bin/catalina.sh start echo start success!! ;; stop) $CATALINA_HOME/bin/catalina.sh stop echo stop success!! ;; restart) $CATALINA_HOME/bin/catalina.sh stop echo stop success!! sleep 3 $CATALINA_HOME/bin/catalina.sh start echo start success!! ;; version) $CATALINA_HOME/bin/catalina.sh version ;; configtest) $CATALINA_HOME/bin/catalina.sh configtest ;; esac exit 0Copy the code

Automatic deployment script:

#! /bin/bash -e
export now_time=$(date +%Y-%m-%d_%H-%M-%S)
echo "deploy time:$now_time"

app=$1
version=$2
mkdir -p war/
#Download the program from the SVN to the war directoryWar = war / ${} app _ ${version}. The war echo "$war" SVN export SVN: / / 192.168.0.253 / release / ${} app _ ${version}. $war war deploy_war () {#Decompress the version to the current directorytarget_dir=war/${app}_${version}_${now_time} unzip -q $war -d $target_dir rm -f appwar ln -sf $target_dir appwar target_ln=`pwd`/appwar echo '<? The XML version = "1.0" encoding = "utf-8"? > <Context docBase="'$target_ln'" allowLinking="false"> </Context>' > conf/Catalina/localhost/ROOT.xml#Restarting the Tomcat Service
./tomcat.sh restart
}

deploy_war
Copy the code

Analysis of Tomcat network communication model

Tomcat supports four thread models

What is the IO?

IO refers to the input and output streams for data transmission. The input and output objects can be files, network services, and memory.

What is the IO model?

Question: Suppose the application is reading a large file from the hard disk. Is the CPU under the same load state as the hard disk?

Presentation:

  • The demo observes whether the CPU fluctuates greatly during reading and writing large files.

Demo result: CPU does not increase too much

IO operations are usually time-consuming, so for efficient use of hardware, an application can use a dedicated thread to perform IO operations while another thread uses the IDLE CPU to perform other calculations. This IO operation method to improve the efficiency of application execution is called IO model.

Brief description of each IO model

describe
BIO Block type IO, that is, Tomcat uses traditional java.io to operate. This mode creates one thread for each request, incurs high performance overhead and is not suitable for high concurrency scenarios. Advantages are stable, suitable for small number of connections and fixed architecture.
NIO Non-blocking IONew IO implemented after jdk1.4. This mode is based on the multiplexing selector to monitor the connection status in the notification thread processing, so as to achieve the purpose of non-blocking. Supports better concurrency performance than traditional BIO. This mode is used by default after Tomcat 8.0
APR Apache Portable Runtime/Apache Portable Runtime), a support library for the Apache HTTP server. To put it simply, Tomcat calls the Apache HTTP server’s core dynamic link library as JNI to handle file reads or network transfers. Use the APR library required to compile and install
AIO Asynchronous non-blocking IO, jdk1.7 support. Unlike NIO, there is no multiplexing selector required. Instead, the request-processing thread completes the procedure, calls back, and continues to perform subsequent operations. Supported after Tomcat 8.

Use the specified IO model configuration mode:

Config <Connector protocol=”HTTP/1.1″> in the server. XML file.

The default configuration is 8.0 protocol= “HTTP/1.1”, which is BIO before 8.0 and NIO after 8.0

  • BIO

Protocol = “org. Apache. Coyote. Http11. Http11Protocol”

  • NIO

Protocol = “org. Apache. Coyote. Http11. Http11NioProtocol”

  • AIO

Protocol = “org. Apache. Coyote. Http11. Http11Nio2Protocol”

  • APR

Protocol = “org. Apache. Coyote. Http11. Http11AprProtocol”

Tomcat BIO, NIO implementation process source code analysis

BIO is different from NIO

How does the BIO and NIO thread count change in a high concurrency scenario?

The configuration of BIO

<Connector port="8080" protocol="org.apache.coyote.http11.Http11Protocol"
               connectionTimeout="20000"
               redirectPort="8443"
               compression="on" compressionMinSize="1024"
               compressableMimeType="text/html,text/xml,text/plain,text/javascript,text/css,application/x-json,application/json,application/x-javascript"
               maxThreads="500" minSpareThreads="1"/>
Copy the code

NIO configuration

 <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
               connectionTimeout="20000"
               redirectPort="8443"
               compression="on" compressionMinSize="1024"
               compressableMimeType="text/html,text/xml,text/plain,text/javascript,text/css,application/x-json,application/json,application/x-javascript"
               maxThreads="500" minSpareThreads="1"/>
Copy the code

Demo data:

Submissions per second BIO Execution thread NIO execution threads
To predict 200 200 threads 20 thread
The experiment of actual 200 55 Wait for threads 23 thread
Simulated production environment 200 229 Run threads 20 wait threads

Important factors in the generation environment:

  1. network
  2. When a program performs business

Source code address: bit-bigdata-transmission

BIO thread model

BIO source

Thread group:

Accept Thread group acceptorThreadCount The default value is 1

Exec thread group maxThread

JIoEndpoint

Acceptor extends Runnable

SocketProcessor extends Runnable

 

NIO thread model

NIO thread model

The Accept thread group defaults to two pollers

Poller Selector PollerEvent Polls the thread status

SocketProcessor  

BIO

The number of threads may be blocked by clients, delayed by network, and slow service processing. === => The number of threads may be larger.

NIO

The number of threads will be affected by slow business processing === => the number of threads will be more.

Interpretation of Tomcat Connector concurrency parameters

The name of the describe
acceptCount Waiting maximum queue
address Bind the client specific address, 127.0.0.1
bufferSize Buffer size per request. bufferSize * maxThreads
compression Whether to enable document compression
compressableMimeTypes text/html,text/xml,text/plain
connectionTimeout Maximum wait time until the client initiates a link to the server for receipt
connectionUploadTimeout Upload connection timeout time
disableUploadTimeout True uses connectionTimeout
enableLookups Disabling DNS query true
keepAliveTimeout Actively close long links when they are idle for a specified period of time, if the client requests this head”connection” “keep-alive”
maxKeepAliveRequests Maximum number of long connections
maxHttpHeaderSize
maxSpareThreads Maximum number of idle threads in BIO mode
MaxThreads (Execution threads) Maximum number of execution threads
MinSpareThreads minSpareThreads 10 Minimum number of idle threads in BIO mode

Tomcat class loading mechanism source code analysis

The nature of class loading

Is used to load the Class. It is responsible for converting the bytecode form of a Class into an in-memory Class object. The bytecode can come from a disk file, a jar package, or a byte stream provided by a remote server. The essence of bytecode is an array of [] bytes with a specific, complex internal format.

JVM running instances can have multiple ClassLoaders, and different classloaders load bytecode files from different places. It can be loaded from different file directories, from different JAR files, or downloaded bytecode from different static file servers on the network.

The hierarchy of classLoaders in the JVMClass loader hierarchy

BootstrapClassLoader

Jar, resources. Jar, charsets. Jar, etc. You can use the following program to get the jar or class files loaded from the class loader:

URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (URL url : urLs) {
    System.out.println(url.toExternalForm());
}
Copy the code

The execution result of the program is as follows:

file:/Library/Java/JavaVirtualMachines/jdk18.. 0 _201.jdk/Contents/Home/jre/lib/resources.jar
file:/Library/Java/JavaVirtualMachines/jdk18.. 0 _201.jdk/Contents/Home/jre/lib/rt.jar
file:/Library/Java/JavaVirtualMachines/jdk18.. 0 _201.jdk/Contents/Home/jre/lib/sunrsasign.jar
file:/Library/Java/JavaVirtualMachines/jdk18.. 0 _201.jdk/Contents/Home/jre/lib/jsse.jar
file:/Library/Java/JavaVirtualMachines/jdk18.. 0 _201.jdk/Contents/Home/jre/lib/jce.jar
file:/Library/Java/JavaVirtualMachines/jdk18.. 0 _201.jdk/Contents/Home/jre/lib/charsets.jar
file:/Library/Java/JavaVirtualMachines/jdk18.. 0 _201.jdk/Contents/Home/jre/lib/jfr.jar
file:/Library/Java/JavaVirtualMachines/jdk18.. 0 _201.jdk/Contents/Home/jre/classes
Copy the code

Select the String class from rt.jar and see what the classloader for the String class is

ClassLoader classLoader = String.class.getClassLoader();
System.out.println(classLoader);
Copy the code

The result is as follows:

null
Copy the code

BootstrapClassLoader is not visible to Java, so null is returned. We can also determine whether a class is loaded using BootstrapClassLoader by checking whether the loader is null.

ExtensionClassLoader

The ExtClassLoader is called the extension class loader. It loads the Java extension class libraries. By default, the ExtClassLoader loads all JAR packages in the JAVA_HOME/jre/lib/ext/ directory or the JAR packages specified by the java.ext.dirs system attribute. Jar packages placed in this directory are visible to the AppClassLoader (because ExtClassLoader is the parent of the AppClassLoader and the Java class loader uses a delegate mechanism).

The ExtClassLoader class scan path can be seen by executing the following code:

String extDirs = System.getProperty("java.ext.dirs");
for (String path : extDirs.split(";")) {
System.out.println(path);
}
Copy the code

The command output is as follows (for Mac OS) :

/Users/hjh/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk18.. 0 _201.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions :/usr/lib/javaCopy the code

The contents in the jre/lib/ext directory are as follows:Choose a random class from the path above to see what its classloader is:

sun.misc.Launcher$ExtClassLoader@4439f31e
null
Copy the code

The parent of the ExtClassLoader is null. BootstrapClassLoader is not visible to Java. The parent loader of ExtClassLoader returns null. Does that mean that the parent loader of ExtClassLoader is BootstrapClassLoader?

Bootstrap ClassLoader is written in C/C++. It is part of the virtual machine itself, so it is not a JAVA class. In other words, it cannot be referenced in JAVA code. When the JVM starts up, the Bootstrap class loader loads the class files in core JAR packages such as rt.jar. The previous int.class and String.class files are loaded by the Bootstrap class loader. Then, as we analyzed earlier, the JVM initializes sun.misc.Launcher and creates Extension ClassLoader and AppClassLoader instances. And set ExtClassLoader as the parent loader of AppClassLoader. Bootstrap does not have a parent loader, but it can act as the parent of a ClassLoader. Such as ExtClassLoader. This also explains why the getParent method of the ExtClassLoader was Null

AppClassLoader

Is a direct loader for our users that loads the JAR packages and directories in the path defined in the Classpath environment variable. It usually loads the code we write ourselves and the third-party JAR packages we use.

Loads the path or JAR specified by System.getProperty(“java.class.path”). You can also override the original Classpath setting by adding -cp when running the program in Java, such as Java -cp./lavasoft/classes HelloWorld

public class AppClassLoaderTest {
    public static void main(String[] args) { System.out.println(ClassLoader.getSystemClassLoader()); }}Copy the code

The following output is displayed:

sun.misc.Launcher$AppClassLoader@18b4aac2
Copy the code

The above conclusion shows that call. This getSystemClassLoader () can get AppClassLoader class loader.

protected ClassLoader(a) {
    this(checkCreateClassLoader(), getSystemClassLoader());
}
Copy the code

By looking at the source code of the ClassLoader, and without specific instructions, any user-defined ClassLoader treats the ClassLoader as the parent of the custom ClassLoader.

Execute the above code to get the load path of the classpath.

The classes in the main function above are loaded using the AppClassLoader, which can be concluded by executing the following code

public class AppClassLoaderTest {

    public static void main(String[] args) {
        ClassLoader classLoader = Test.class.getClassLoader();
        System.out.println(classLoader);
        System.out.println(classLoader.getParent());
    }

    private static class Test {}}Copy the code

The result is as follows:

sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@2d209079
Copy the code

The parent loader of AppClassLoader is ExtClassLoader

The class loading order of Tomcat

In Tomcat, the default behavior is to first try to load the type in Bootstrap and Extension, then load it in Webapp ClassLoader if it can’t find it, and then look it up in Common.

NoClassDefFoundError

NoClassDefFoundError is a common problem in developing JavaEE programs. This problem is compounded by the complexity of the JavaEE middleware environment you are using and the sheer volume of the application itself, especially as JavaEE servers today have a large number of class loaders. NoClassDefFoundError in JavaDoc occurs when a JVM or class loader instance tries to load a definition of a type, but the definition is not found, affecting the execution path. In other words, the class can be found at compile time, but not at execution time. There is no error alert from the IDE at this point, but an error occurs at runtime.

NoSuchMethodError

In another scenario, we might encounter another error, namely NoSuchMethodError. NoSuchMethodError indicates that the type does exist, but an incorrect version has been loaded.

ClassCastException

ClassCastException, in the case of A classloader, usually occurs during A transition operation, such as: A A = (A) method(); , it’s easy to tell that the method() method returns A type other than type A, but in A JavaEE environment with multiple classloaders, some difficult situations can occur.

Some pictures from the network, copyright to the original author, delete.Copy the code