移除Maven pom.xml中war解决ClassNotFoundException,求底层原理解析
Nice catch on solving this by removing the <war> packaging—let's dig into why this worked and what was causing that frustrating ClassNotFoundException in the first place.
Why Did You Get ClassNotFoundException: org.apache.commons.io.FileUtils?
This error boils down to one core issue: the JVM couldn't find the FileUtils class in its runtime classpath. For your specific scenario, there are two likely culprits tied to using war packaging:
- Your
commons-iodependency might have been marked with aprovidedscope. When building a war, Maven assumesprovideddependencies are supplied by your web container (like Tomcat), so it doesn't package them intoWEB-INF/lib. If you weren't running the app in a container (e.g., running a main method directly), there's no way the JVM could find this class. - War files have a structure optimized for web containers, not standalone Java apps. All dependencies live under
WEB-INF/lib, but the JVM doesn't automatically scan this directory when running a regular Java program. Even ifcommons-iowas inWEB-INF/lib, your runtime setup wouldn't pick it up.
The Underlying Logic of Removing the <war> Packaging
Maven's packaging setting dictates how it builds your project, handles dependencies, and structures the output:
- When using
<packaging>war</packaging>:- Maven follows web app conventions: it sorts dependencies into
WEB-INF/lib(forcompile/runtimescopes) or ignores them entirely (forprovidedscopes, since containers are supposed to supply them). - This structure works great for deploying to Tomcat or Jetty, but fails for standalone runs—since the JVM doesn't know to look in
WEB-INF/libfor classes.
- Maven follows web app conventions: it sorts dependencies into
- When you remove the
warpackaging (Maven defaults tojar):- Maven switches to handling dependencies like a standard Java application:
- All
compileandruntimedependencies are included in the runtime classpath. If you run the app via Maven'sexecplugin, it automatically adds these dependencies to the JVM's classpath arguments. - If you build an executable JAR, plugins like
maven-shade-pluginormaven-assembly-pluginwill either bundle dependencies into the JAR or generate aMANIFEST.MFthat points to the correct dependency paths.
- All
- This aligns the dependency handling with how a standalone Java program expects to find classes, so the JVM can locate
FileUtilswithout issues.
- Maven switches to handling dependencies like a standard Java application:
To put it simply: Your original war packaging was optimized for web containers, but your runtime environment didn't match that context. Switching to jar packaging told Maven to use dependency rules that fit a regular Java app, fixing the classpath mismatch that caused the error.
内容的提问来源于stack exchange,提问作者yuzhen

